diff options
-rw-r--r-- | src/adlmidi.cpp | 216 | ||||
-rw-r--r-- | src/adlmidi.h | 8 |
2 files changed, 135 insertions, 89 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 246f5f7..a994fa0 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -415,7 +415,9 @@ class MIDIplay std::vector<TrackInfo> track; Position(): began(false), wait(0.0), track() { } - } CurrentPosition, LoopBeginPosition; + }; + Position CurrentPosition, LoopBeginPosition, trackBeginPosition; + std::map<std::string, unsigned> devices; std::map<unsigned/*track*/, unsigned/*channel begin index*/> current_device; @@ -515,8 +517,12 @@ class MIDIplay public: std::string musTitle; fraction<long> InvDeltaTicks, Tempo; - bool loopStart, loopEnd, invalidLoop; - long loopStart_ticks, loopEnd_ticks; + bool trackStart, + loopStart, + loopEnd, + loopStart_passed /*Tells that "loopStart" already passed*/, + invalidLoop /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/, + loopStart_hit /*loopStart entry was hited in previous tick*/; OPL3 opl; public: static unsigned long ReadBEInt(const void* buffer, unsigned nbytes) @@ -830,8 +836,11 @@ public: CurrentPosition.track[tk].delay = ReadVarLen(tk); } } - loopStart = true; + trackStart = true; + loopStart = true; + loopStart_passed = false; invalidLoop = false; + loopStart_hit = false; opl.Reset(); // Reset AdLib //opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously) @@ -1029,17 +1038,33 @@ private: // ^HACK: CHRONO TRIGGER LOOP */ + if(loopStart_hit && (loopStart||loopEnd)) //Avoid invalid loops + { + invalidLoop=true; + loopStart = false; + loopEnd = false; + LoopBeginPosition=trackBeginPosition; + } else { + loopStart_hit=false; + } + if(loopStart) { + if(trackStart) + { + trackBeginPosition=RowBeginPosition; + trackStart=false; + } LoopBeginPosition = RowBeginPosition; loopStart = false; + loopStart_hit=true; } if(shortest < 0 || loopEnd) { // Loop if song end reached loopEnd = false; CurrentPosition = LoopBeginPosition; - shortest = 0; + shortest = 0; if(opl._parent->QuitWithoutLooping==1) { opl._parent->QuitFlag = 1; @@ -1068,8 +1093,28 @@ private: CurrentPosition.track[tk].ptr += length; if(evtype == 0x2F) { CurrentPosition.track[tk].status = -1; return; } if(evtype == 0x51) { Tempo = InvDeltaTicks * fraction<long>( (long) ReadBEInt(data.data(), data.size())); return; } - if(evtype == 6 && data == "loopStart") loopStart = true; - if(evtype == 6 && data == "loopEnd" ) loopEnd = true; + if(evtype == 6) + { + for(size_t i=0;i<data.size();i++) + { + if(data[i]<='Z' && data[i]>='A') + data[i]=data[i]-('Z'-'z'); + } + + if( (data == "loopstart") && (!invalidLoop) ) + { + loopStart = true; + loopStart_passed=true; + } + + if( (data == "loopend") && (!invalidLoop) ) + { + if((loopStart_passed) && (!loopStart)) + loopEnd=true; + else + invalidLoop=true; + } + } if(evtype == 9) current_device[tk] = ChooseDevice(data); // if(evtype >= 1 && evtype <= 6) // UI.PrintLn("Meta %d: %s", evtype, data.c_str()); @@ -1801,47 +1846,6 @@ int adlRefreshNumCards(ADL_MIDIPlayer* device) return 0; } -struct Mixx -{ - static int requested_len; //size of target buffer - static int stored_samples; //num of collected samples - static int backup_samples[1024]; //Backup sample storage. - static int backup_samples_size; //Backup sample storage. - //If requested number of samples less than 512 bytes, backup will be stored - - static int *_len; - static int *_out; - static void SendStereoAudio(unsigned long count, int* samples) - { - if(!count) return; - stored_samples=0; - size_t pos=(*_len); - for(unsigned long p = 0; p < count; ++p) - for(unsigned w=0; w<2; ++w) - { - int out=samples[p*2+w]; - int offset=pos+p*2+w; - if(offset<requested_len) - _out[offset] = out; - else - { - backup_samples[backup_samples_size]=out; - backup_samples_size++; stored_samples++; - } - } - } - -}; - -int Mixx::requested_len=0; -int Mixx::stored_samples=0; -int Mixx::backup_samples[1024]; -int Mixx::backup_samples_size=0; -int *Mixx::_len=NULL; -int *Mixx::_out=NULL; - - - /*---------------------------EXPORTS---------------------------*/ ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate) @@ -1863,6 +1867,10 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate) _device->carry=0.0; _device->mindelay = 1.0 / (double)_device->PCM_RATE; _device->maxdelay = 512.0 / (double)_device->PCM_RATE; + + _device->stored_samples=0; + _device->backup_samples_size=0; + _device->adl_midiPlayer = (void*)new MIDIplay; ((MIDIplay*)_device->adl_midiPlayer)->opl._parent=_device; ((MIDIplay*)_device->adl_midiPlayer)->opl.NumCards=_device->NumCards; @@ -1872,7 +1880,7 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate) ((MIDIplay*)_device->adl_midiPlayer)->opl.HighVibratoMode=(bool)_device->HighVibratoMode; ((MIDIplay*)_device->adl_midiPlayer)->opl.AdlPercussionMode=(bool)_device->AdlPercussionMode; ((MIDIplay*)_device->adl_midiPlayer)->opl.ScaleModulators=(bool)_device->ScaleModulators; - ((MIDIplay*)(_device->adl_midiPlayer))->ChooseDevice(""); + ((MIDIplay*)(_device->adl_midiPlayer))->ChooseDevice(""); adlRefreshNumCards(_device); return _device; } @@ -1961,9 +1969,10 @@ ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath) { - Mixx::backup_samples_size=0; if(device && device->adl_midiPlayer) { + device->stored_samples=0; + device->backup_samples_size=0; if(!((MIDIplay *)device->adl_midiPlayer)->LoadMIDI(filePath)) { ADLMIDI_ErrorString="ADL MIDI: Can't load file"; @@ -1976,9 +1985,10 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath) ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer* device, void *mem, long size) { - Mixx::backup_samples_size=0; if(device && device->adl_midiPlayer) { + device->stored_samples=0; + device->backup_samples_size=0; if(!((MIDIplay *)device->adl_midiPlayer)->LoadMIDI(mem, size)) { ADLMIDI_ErrorString="ADL MIDI: Can't load data from memory"; @@ -2003,8 +2013,10 @@ ADLMIDI_EXPORT const char *adl_getMusicTitle(ADL_MIDIPlayer *device) ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device) { - Mixx::backup_samples_size=0; - if(device->adl_midiPlayer) delete ((MIDIplay*)(device->adl_midiPlayer)); + if(device->adl_midiPlayer) + { + delete ((MIDIplay*)(device->adl_midiPlayer)); + } device->adl_midiPlayer = NULL; free(device); device=NULL; @@ -2013,42 +2025,73 @@ ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device) ADLMIDI_EXPORT void adl_reset(ADL_MIDIPlayer *device) { if(!device) return; - Mixx::backup_samples_size=0; + device->stored_samples=0; + device->backup_samples_size=0; ((MIDIplay*)device->adl_midiPlayer)->opl.Reset(); } -ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out) +inline static void SendStereoAudio(ADL_MIDIPlayer*device, + int& samples_requested, + unsigned long& in_size, + int* _in, + int out_pos, + short* _out) +{ + if(!in_size) return; + device->stored_samples=0; + int out; + int offset; + for(unsigned long p = 0; p < in_size; ++p) + { + for(unsigned w=0; w<2; ++w) + { + out = _in[p*2+w]; + offset = out_pos+p*2+w; + if(offset<samples_requested) + { + _out[offset] = (short)out; + } + else + { + device->backup_samples[device->backup_samples_size]=out; + device->backup_samples_size++; device->stored_samples++; + } + } + } +} + + +ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, short *out) { if(!device) return 0; + sampleCount -= sampleCount%2;//Avoid non-odd sample requests if(sampleCount<0) return 0; if(device->QuitFlag) return 0; int gotten_len=0; - Mixx::requested_len=sampleCount; - Mixx::_len=&gotten_len; - Mixx::_out=out; unsigned long n_samples=512; unsigned long n_samples_2=n_samples*2; - while(sampleCount>0) + int left = sampleCount; + while(left>0) { - if(Mixx::backup_samples_size>0) + if(device->backup_samples_size>0) { //Send reserved samples if exist int ate=0; - while((ate<Mixx::backup_samples_size) && (ate<sampleCount)) + while((ate<device->backup_samples_size) && (ate<left)) { - out[ate]=Mixx::backup_samples[ate]; ate++; + out[ate]=(short)device->backup_samples[ate]; ate++; } - sampleCount-=ate; + left-=ate; gotten_len+=ate; - if(ate<Mixx::backup_samples_size) + if(ate<device->backup_samples_size) { for(int j=0; j<ate; j++) - Mixx::backup_samples[(ate-1)-j]=Mixx::backup_samples[(Mixx::backup_samples_size-1)-j]; + device->backup_samples[(ate-1)-j]=device->backup_samples[(device->backup_samples_size-1)-j]; } - Mixx::backup_samples_size-=ate; + device->backup_samples_size-=ate; } else { const double eat_delay = device->delay < device->maxdelay ? device->delay : device->maxdelay; device->delay -= eat_delay; @@ -2061,36 +2104,35 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out) device->SkipForward -= 1; else { - sampleCount-=n_samples_2; + left -= n_samples_2; + int buf[n_samples*2]; + unsigned long in_count=n_samples; + if(device->NumCards == 1) { - ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[0].Generate(0, Mixx::SendStereoAudio, n_samples); + ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[0].GenerateArr(buf, &in_count); + /* Process it */ + SendStereoAudio(device, sampleCount, in_count, buf, gotten_len, out); } else if(n_samples > 0) { - /* Mix together the audio from different cards */ - static std::vector<int> sample_buf; - sample_buf.clear(); - sample_buf.resize(n_samples*2); - struct Mix - { - static void AddStereoAudio(unsigned long count, int* samples) - { - for(unsigned long a=0; a<count*2; ++a) - sample_buf[a] += samples[a]; - } - }; + int in[n_samples*2]; + + //fill buffer with zeros + for(unsigned long a=0; a<(in_count*2); ++a) buf[a] = 0; + + unsigned long in_count = n_samples; for(unsigned card = 0; card < device->NumCards; ++card) { - ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[card].Generate( - 0, - Mix::AddStereoAudio, - n_samples); + ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[card].GenerateArr( in, &in_count ); + for(unsigned long a=0; a<(in_count*2); ++a) + buf[a] += in[a]; } + /* Process it */ - Mixx::SendStereoAudio(n_samples, &sample_buf[0]); + SendStereoAudio(device, sampleCount, in_count, buf, gotten_len, out); } - gotten_len += (n_samples*2)-Mixx::stored_samples; + gotten_len += (n_samples*2)-device->stored_samples; } device->delay = ((MIDIplay*)device->adl_midiPlayer)->Tick(eat_delay, device->mindelay); } @@ -2099,8 +2141,6 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out) } - - #ifdef ADLMIDI_buildAsApp int main(int argc, char** argv) diff --git a/src/adlmidi.h b/src/adlmidi.h index 75ae8a5..7e8bbd6 100644 --- a/src/adlmidi.h +++ b/src/adlmidi.h @@ -47,6 +47,12 @@ struct ADL_MIDIPlayer { double mindelay; double maxdelay; + /*For internal usage*/ + int stored_samples; //num of collected samples + int backup_samples[1024]; //Backup sample storage. + int backup_samples_size; //Backup sample storage. + /*For internal usage*/ + void *adl_midiPlayer; unsigned long PCM_RATE; }; @@ -94,7 +100,7 @@ extern void adl_reset(struct ADL_MIDIPlayer*device); extern void adl_close(struct ADL_MIDIPlayer *device); /*Take a sample buffer*/ -extern int adl_play(struct ADL_MIDIPlayer*device, int sampleCount, int out []); +extern int adl_play(struct ADL_MIDIPlayer*device, int sampleCount, short out[]); #ifdef __cplusplus } |