123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /*
- * libopenmpt_modplug.c
- * --------------------
- * Purpose: libopenmpt emulation of the libmodplug interface
- * Notes : (currently none)
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #ifndef NO_LIBMODPLUG
- #ifdef LIBOPENMPT_BUILD_DLL
- #undef LIBOPENMPT_BUILD_DLL
- #endif
- #ifdef _MSC_VER
- #ifndef _CRT_SECURE_NO_WARNINGS
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #endif /* _MSC_VER */
- #include <libopenmpt/libopenmpt.h>
- #include <limits.h>
- #include <math.h>
- #include <memory.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MODPLUG_BUILD
- #ifdef _MSC_VER
- #ifdef MPT_BUILD_MSVC_SHARED
- #define DLL_EXPORT
- #endif /* MPT_BUILD_MSVC_SHARED */
- #ifdef MPT_BUILD_MSVC_STATIC
- #define MODPLUG_STATIC
- #endif /* MPT_BUILD_MSVC_STATIC */
- #endif /* _MSC_VER */
- #ifdef _MSC_VER
- #define LIBOPENMPT_MODPLUG_API
- #else /* !_MSC_VER */
- #define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT
- #endif /* _MSC_VER */
- #include "libmodplug/modplug.h"
- /* from libmodplug/sndfile.h */
- /* header is not c clean */
- #define MIXING_ATTENUATION 4
- #define MOD_TYPE_NONE 0x0
- #define MOD_TYPE_MOD 0x1
- #define MOD_TYPE_S3M 0x2
- #define MOD_TYPE_XM 0x4
- #define MOD_TYPE_MED 0x8
- #define MOD_TYPE_MTM 0x10
- #define MOD_TYPE_IT 0x20
- #define MOD_TYPE_669 0x40
- #define MOD_TYPE_ULT 0x80
- #define MOD_TYPE_STM 0x100
- #define MOD_TYPE_FAR 0x200
- #define MOD_TYPE_WAV 0x400
- #define MOD_TYPE_AMF 0x800
- #define MOD_TYPE_AMS 0x1000
- #define MOD_TYPE_DSM 0x2000
- #define MOD_TYPE_MDL 0x4000
- #define MOD_TYPE_OKT 0x8000
- #define MOD_TYPE_MID 0x10000
- #define MOD_TYPE_DMF 0x20000
- #define MOD_TYPE_PTM 0x40000
- #define MOD_TYPE_DBM 0x80000
- #define MOD_TYPE_MT2 0x100000
- #define MOD_TYPE_AMF0 0x200000
- #define MOD_TYPE_PSM 0x400000
- #define MOD_TYPE_J2B 0x800000
- #define MOD_TYPE_ABC 0x1000000
- #define MOD_TYPE_PAT 0x2000000
- #define MOD_TYPE_UMX 0x80000000 // Fake type
- #define BUFFER_COUNT 1024
- struct _ModPlugFile {
- openmpt_module* mod;
- signed short* buf;
- signed int* mixerbuf;
- char* name;
- char* message;
- ModPlug_Settings settings;
- ModPlugMixerProc mixerproc;
- ModPlugNote** patterns;
- };
- static ModPlug_Settings globalsettings = {
- MODPLUG_ENABLE_OVERSAMPLING|MODPLUG_ENABLE_NOISE_REDUCTION,
- 2,
- 16,
- 44100,
- MODPLUG_RESAMPLE_LINEAR,
- 128,
- 256,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- };
- static int32_t modplugresamplingmode_to_filterlength(int mode)
- {
- if(mode<0){
- return 1;
- }
- switch(mode){
- case MODPLUG_RESAMPLE_NEAREST: return 1; break;
- case MODPLUG_RESAMPLE_LINEAR: return 2; break;
- case MODPLUG_RESAMPLE_SPLINE: return 4; break;
- case MODPLUG_RESAMPLE_FIR: return 8; break;
- }
- return 8;
- }
- LIBOPENMPT_MODPLUG_API ModPlugFile* ModPlug_Load(const void* data, int size)
- {
- ModPlugFile* file = malloc(sizeof(ModPlugFile));
- const char* name = NULL;
- const char* message = NULL;
- if(!file) return NULL;
- memset(file,0,sizeof(ModPlugFile));
- memcpy(&file->settings,&globalsettings,sizeof(ModPlug_Settings));
- file->mod = openmpt_module_create_from_memory2(data,size,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
- if(!file->mod){
- free(file);
- return NULL;
- }
- file->buf = malloc(BUFFER_COUNT*sizeof(signed short)*4);
- if(!file->buf){
- openmpt_module_destroy(file->mod);
- free(file);
- return NULL;
- }
- openmpt_module_set_repeat_count(file->mod,file->settings.mLoopCount);
- name = openmpt_module_get_metadata(file->mod,"title");
- if(name){
- file->name = malloc(strlen(name)+1);
- if(file->name){
- strcpy(file->name,name);
- }
- openmpt_free_string(name);
- name = NULL;
- }else{
- file->name = malloc(strlen("")+1);
- if(file->name){
- strcpy(file->name,"");
- }
- }
- message = openmpt_module_get_metadata(file->mod,"message");
- if(message){
- file->message = malloc(strlen(message)+1);
- if(file->message){
- strcpy(file->message,message);
- }
- openmpt_free_string(message);
- message = NULL;
- }else{
- file->message = malloc(strlen("")+1);
- if(file->message){
- strcpy(file->message,"");
- }
- }
- openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT,file->settings.mStereoSeparation*100/128);
- openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH,modplugresamplingmode_to_filterlength(file->settings.mResamplingMode));
- return file;
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_Unload(ModPlugFile* file)
- {
- int p;
- if(!file) return;
- if(file->patterns){
- for(p=0;p<openmpt_module_get_num_patterns(file->mod);p++){
- if(file->patterns[p]){
- free(file->patterns[p]);
- file->patterns[p] = NULL;
- }
- }
- free(file->patterns);
- file->patterns = NULL;
- }
- if(file->mixerbuf){
- free(file->mixerbuf);
- file->mixerbuf = NULL;
- }
- openmpt_module_destroy(file->mod);
- file->mod = NULL;
- free(file->name);
- file->name = NULL;
- free(file->message);
- file->message = NULL;
- free(file->buf);
- file->buf = NULL;
- free(file);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_Read(ModPlugFile* file, void* buffer, int size)
- {
- int framesize;
- int framecount;
- int frames;
- int rendered;
- int frame;
- int channel;
- int totalrendered;
- signed short* in;
- signed int* mixbuf;
- unsigned char* buf8;
- signed short* buf16;
- signed int* buf32;
- if(!file) return 0;
- framesize = file->settings.mBits/8*file->settings.mChannels;
- framecount = size/framesize;
- buf8 = buffer;
- buf16 = buffer;
- buf32 = buffer;
- totalrendered = 0;
- while(framecount>0){
- frames = framecount;
- if(frames>BUFFER_COUNT){
- frames = BUFFER_COUNT;
- }
- if(file->settings.mChannels==1){
- rendered = (int)openmpt_module_read_mono(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0]);
- }else if(file->settings.mChannels==2){
- rendered = (int)openmpt_module_read_stereo(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0],&file->buf[frames*1]);
- }else if(file->settings.mChannels==4){
- rendered = (int)openmpt_module_read_quad(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0],&file->buf[frames*1],&file->buf[frames*2],&file->buf[frames*3]);
- }else{
- return 0;
- }
- in = file->buf;
- if(file->mixerproc&&file->mixerbuf){
- mixbuf=file->mixerbuf;
- for(frame=0;frame<frames;frame++){
- for(channel=0;channel<file->settings.mChannels;channel++){
- *mixbuf = in[frames*channel+frame]<<(32-16-1-MIXING_ATTENUATION);
- mixbuf++;
- }
- }
- file->mixerproc(file->mixerbuf,file->settings.mChannels*frames,file->settings.mChannels);
- mixbuf=file->mixerbuf;
- for(frame=0;frame<frames;frame++){
- for(channel=0;channel<file->settings.mChannels;channel++){
- in[frames*channel+frame] = *mixbuf>>(32-16-1-MIXING_ATTENUATION);
- mixbuf++;
- }
- }
- }
- if(file->settings.mBits==8){
- for(frame=0;frame<frames;frame++){
- for(channel=0;channel<file->settings.mChannels;channel++){
- *buf8 = in[frames*channel+frame]/256+0x80;
- buf8++;
- }
- }
- }else if(file->settings.mBits==16){
- for(frame=0;frame<frames;frame++){
- for(channel=0;channel<file->settings.mChannels;channel++){
- *buf16 = in[frames*channel+frame];
- buf16++;
- }
- }
- }else if(file->settings.mBits==32){
- for(frame=0;frame<frames;frame++){
- for(channel=0;channel<file->settings.mChannels;channel++){
- *buf32 = in[frames*channel+frame] << (32-16-1-MIXING_ATTENUATION);
- buf32++;
- }
- }
- }else{
- return 0;
- }
- totalrendered += rendered;
- framecount -= frames;
- if(!rendered) break;
- }
- memset(((char*)buffer)+totalrendered*framesize,0,size-totalrendered*framesize);
- return totalrendered*framesize;
- }
- LIBOPENMPT_MODPLUG_API const char* ModPlug_GetName(ModPlugFile* file)
- {
- if(!file) return NULL;
- return file->name;
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetLength(ModPlugFile* file)
- {
- if(!file) return 0;
- return (int)(openmpt_module_get_duration_seconds(file->mod)*1000.0);
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_Seek(ModPlugFile* file, int millisecond)
- {
- if(!file) return;
- openmpt_module_set_position_seconds(file->mod,(double)millisecond*0.001);
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_GetSettings(ModPlug_Settings* settings)
- {
- if(!settings) return;
- memcpy(settings,&globalsettings,sizeof(ModPlug_Settings));
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_SetSettings(const ModPlug_Settings* settings)
- {
- if(!settings) return;
- memcpy(&globalsettings,settings,sizeof(ModPlug_Settings));
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_GetMasterVolume(ModPlugFile* file)
- {
- int32_t val;
- if(!file) return 0;
- val = 0;
- if(!openmpt_module_get_render_param(file->mod,OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL,&val)) return 128;
- return (unsigned int)(128.0*pow(10.0,val*0.0005));
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol)
- {
- if(!file) return;
- openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL,(int32_t)(2000.0*log10(cvol/128.0)));
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentSpeed(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_speed(file->mod);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentTempo(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_tempo(file->mod);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentOrder(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_order(file->mod);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentPattern(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_pattern(file->mod);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentRow(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_row(file->mod);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetPlayingChannels(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_current_playing_channels(file->mod);
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_SeekOrder(ModPlugFile* file,int order)
- {
- if(!file) return;
- openmpt_module_set_position_order_row(file->mod,order,0);
- }
- LIBOPENMPT_MODPLUG_API int ModPlug_GetModuleType(ModPlugFile* file)
- {
- const char* type;
- int retval;
- if(!file) return 0;
- type = openmpt_module_get_metadata(file->mod,"type");
- retval = MOD_TYPE_NONE;
- if(!type){
- return retval;
- }
- if(!strcmp(type,"mod")){
- retval = MOD_TYPE_MOD;
- }else if(!strcmp(type,"s3m")){
- retval = MOD_TYPE_S3M;
- }else if(!strcmp(type,"xm")){
- retval = MOD_TYPE_XM;
- }else if(!strcmp(type,"med")){
- retval = MOD_TYPE_MED;
- }else if(!strcmp(type,"mtm")){
- retval = MOD_TYPE_MTM;
- }else if(!strcmp(type,"it")){
- retval = MOD_TYPE_IT;
- }else if(!strcmp(type,"669")){
- retval = MOD_TYPE_669;
- }else if(!strcmp(type,"ult")){
- retval = MOD_TYPE_ULT;
- }else if(!strcmp(type,"stm")){
- retval = MOD_TYPE_STM;
- }else if(!strcmp(type,"far")){
- retval = MOD_TYPE_FAR;
- }else if(!strcmp(type,"s3m")){
- retval = MOD_TYPE_WAV;
- }else if(!strcmp(type,"amf")){
- retval = MOD_TYPE_AMF;
- }else if(!strcmp(type,"ams")){
- retval = MOD_TYPE_AMS;
- }else if(!strcmp(type,"dsm")){
- retval = MOD_TYPE_DSM;
- }else if(!strcmp(type,"mdl")){
- retval = MOD_TYPE_MDL;
- }else if(!strcmp(type,"okt")){
- retval = MOD_TYPE_OKT;
- }else if(!strcmp(type,"mid")){
- retval = MOD_TYPE_MID;
- }else if(!strcmp(type,"dmf")){
- retval = MOD_TYPE_DMF;
- }else if(!strcmp(type,"ptm")){
- retval = MOD_TYPE_PTM;
- }else if(!strcmp(type,"dbm")){
- retval = MOD_TYPE_DBM;
- }else if(!strcmp(type,"mt2")){
- retval = MOD_TYPE_MT2;
- }else if(!strcmp(type,"amf0")){
- retval = MOD_TYPE_AMF0;
- }else if(!strcmp(type,"psm")){
- retval = MOD_TYPE_PSM;
- }else if(!strcmp(type,"j2b")){
- retval = MOD_TYPE_J2B;
- }else if(!strcmp(type,"abc")){
- retval = MOD_TYPE_ABC;
- }else if(!strcmp(type,"pat")){
- retval = MOD_TYPE_PAT;
- }else if(!strcmp(type,"umx")){
- retval = MOD_TYPE_UMX;
- }else{
- retval = MOD_TYPE_IT; /* fallback, most complex type */
- }
- openmpt_free_string(type);
- return retval;
- }
- LIBOPENMPT_MODPLUG_API char* ModPlug_GetMessage(ModPlugFile* file)
- {
- if(!file) return NULL;
- return file->message;
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumInstruments(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_num_instruments(file->mod);
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumSamples(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_num_samples(file->mod);
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumPatterns(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_num_patterns(file->mod);
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumChannels(ModPlugFile* file)
- {
- if(!file) return 0;
- return openmpt_module_get_num_channels(file->mod);
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff)
- {
- const char* str;
- char buf[32];
- if(!file) return 0;
- str = openmpt_module_get_sample_name(file->mod,qual-1);
- memset(buf,0,32);
- if(str){
- strncpy(buf,str,31);
- openmpt_free_string(str);
- }
- if(buff){
- strncpy(buff,buf,32);
- }
- return (unsigned int)strlen(buf);
- }
- LIBOPENMPT_MODPLUG_API unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff)
- {
- const char* str;
- char buf[32];
- if(!file) return 0;
- str = openmpt_module_get_instrument_name(file->mod,qual-1);
- memset(buf,0,32);
- if(str){
- strncpy(buf,str,31);
- openmpt_free_string(str);
- }
- if(buff){
- strncpy(buff,buf,32);
- }
- return (unsigned int)strlen(buf);
- }
- LIBOPENMPT_MODPLUG_API ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows)
- {
- int c;
- int r;
- int numr;
- int numc;
- ModPlugNote note;
- if(!file) return NULL;
- if(numrows){
- *numrows = openmpt_module_get_pattern_num_rows(file->mod,pattern);
- }
- if(pattern<0||pattern>=openmpt_module_get_num_patterns(file->mod)){
- return NULL;
- }
- if(!file->patterns){
- file->patterns = malloc(sizeof(ModPlugNote*)*openmpt_module_get_pattern_num_rows(file->mod,pattern));
- if(!file->patterns) return NULL;
- memset(file->patterns,0,sizeof(ModPlugNote*)*openmpt_module_get_pattern_num_rows(file->mod,pattern));
- }
- if(!file->patterns[pattern]){
- file->patterns[pattern] = malloc(sizeof(ModPlugNote)*openmpt_module_get_pattern_num_rows(file->mod,pattern)*openmpt_module_get_num_channels(file->mod));
- if(!file->patterns[pattern]) return NULL;
- memset(file->patterns[pattern],0,sizeof(ModPlugNote)*openmpt_module_get_pattern_num_rows(file->mod,pattern)*openmpt_module_get_num_channels(file->mod));
- }
- numr = openmpt_module_get_pattern_num_rows(file->mod,pattern);
- numc = openmpt_module_get_num_channels(file->mod);
- for(r=0;r<numr;r++){
- for(c=0;c<numc;c++){
- memset(¬e,0,sizeof(ModPlugNote));
- note.Note = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_NOTE);
- note.Instrument = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_INSTRUMENT);
- note.VolumeEffect = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_VOLUMEEFFECT);
- note.Effect = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_EFFECT);
- note.Volume = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_VOLUME);
- note.Parameter = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_PARAMETER);
- memcpy(&file->patterns[pattern][r*numc+c],¬e,sizeof(ModPlugNote));
- }
- }
- return file->patterns[pattern];
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc)
- {
- if(!file) return;
- if(!file->mixerbuf){
- file->mixerbuf = malloc(BUFFER_COUNT*sizeof(signed int)*4);
- }
- file->mixerproc = proc;
- }
- LIBOPENMPT_MODPLUG_API void ModPlug_UnloadMixerCallback(ModPlugFile* file)
- {
- if(!file) return;
- file->mixerproc = NULL;
- if(file->mixerbuf){
- free(file->mixerbuf);
- file->mixerbuf = NULL;
- }
- }
- LIBOPENMPT_MODPLUG_API char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath)
- {
- (void)file;
- /* not implemented */
- fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportS3M(%s) not implemented.\n",filepath);
- return 0;
- }
- LIBOPENMPT_MODPLUG_API char ModPlug_ExportXM(ModPlugFile* file, const char* filepath)
- {
- (void)file;
- /* not implemented */
- fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportXM(%s) not implemented.\n",filepath);
- return 0;
- }
- LIBOPENMPT_MODPLUG_API char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath)
- {
- (void)file;
- /* not implemented */
- fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportMOD(%s) not implemented.\n",filepath);
- return 0;
- }
- LIBOPENMPT_MODPLUG_API char ModPlug_ExportIT(ModPlugFile* file, const char* filepath)
- {
- (void)file;
- /* not implemented */
- fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportIT(%s) not implemented.\n",filepath);
- return 0;
- }
- #endif /* NO_LIBMODPLUG */
|