diff options
author | Wohlstand <admin@wohlnet.ru> | 2017-10-18 02:22:01 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2017-10-18 02:22:01 +0300 |
commit | 380d08e1a234efb17cf15a6b6c2d00c52e4fc648 (patch) | |
tree | 563567a5615623db8e9e3acdffa3be8f44cb84ba /src/adlmidi.cpp | |
parent | d7b33b8d4fc3efe90d8e388d451966fa4baefba6 (diff) | |
download | libADLMIDI-380d08e1a234efb17cf15a6b6c2d00c52e4fc648.tar.gz libADLMIDI-380d08e1a234efb17cf15a6b6c2d00c52e4fc648.tar.bz2 libADLMIDI-380d08e1a234efb17cf15a6b6c2d00c52e4fc648.zip |
Smooth finalizing, rewinding, and a bit more crash safety
* Smooth finalizing of song when loop is disabled (old ugly hack has been removed :wink:)
* Added an ability to reset song position to begin (very helpful when song reaches the end)
* Avoided possible crashes on attempt to fetch sample data without opening of MIDI file
Diffstat (limited to 'src/adlmidi.cpp')
-rw-r--r-- | src/adlmidi.cpp | 277 |
1 files changed, 53 insertions, 224 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 79c1422..11b7c9b 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -23,52 +23,47 @@ #include "adlmidi_private.hpp" -#ifdef ADLMIDI_buildAsApp -#define SDL_MAIN_HANDLED -#include <SDL2/SDL.h> -#endif - static const unsigned MaxCards = 100; /*---------------------------EXPORTS---------------------------*/ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) { - ADL_MIDIPlayer *_device; - _device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer)); - _device->PCM_RATE = static_cast<unsigned long>(sample_rate); - _device->AdlBank = 0; - _device->NumFourOps = 7; - _device->NumCards = 2; - _device->HighTremoloMode = 0; - _device->HighVibratoMode = 0; - _device->AdlPercussionMode = 0; - _device->LogarithmicVolumes = 0; - _device->QuitFlag = 0; - _device->SkipForward = 0; - _device->QuitWithoutLooping = 0; - _device->ScaleModulators = 0; - _device->delay = 0.0; - _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; + ADL_MIDIPlayer *midi_device; + midi_device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer)); + midi_device->PCM_RATE = static_cast<unsigned long>(sample_rate); + midi_device->AdlBank = 0; + midi_device->NumFourOps = 7; + midi_device->NumCards = 2; + midi_device->HighTremoloMode = 0; + midi_device->HighVibratoMode = 0; + midi_device->AdlPercussionMode = 0; + midi_device->LogarithmicVolumes = 0; + midi_device->SkipForward = 0; + midi_device->QuitWithoutLooping = 0; + midi_device->ScaleModulators = 0; + midi_device->delay = 0.0; + midi_device->carry = 0.0; + midi_device->mindelay = 1.0 / (double)midi_device->PCM_RATE; + midi_device->maxdelay = 512.0 / (double)midi_device->PCM_RATE; + midi_device->stored_samples = 0; + midi_device->backup_samples_size = 0; + MIDIplay *player = new MIDIplay; - _device->adl_midiPlayer = player; - player->config = _device; - player->opl._parent = _device; - player->opl.NumCards = _device->NumCards; - player->opl.AdlBank = _device->AdlBank; - player->opl.NumFourOps = _device->NumFourOps; - player->opl.LogarithmicVolumes = (bool)_device->LogarithmicVolumes; - player->opl.HighTremoloMode = (bool)_device->HighTremoloMode; - player->opl.HighVibratoMode = (bool)_device->HighVibratoMode; - player->opl.AdlPercussionMode = (bool)_device->AdlPercussionMode; - player->opl.ScaleModulators = (bool)_device->ScaleModulators; + midi_device->adl_midiPlayer = player; + player->config = midi_device; + player->opl._parent = midi_device; + player->opl.NumCards = midi_device->NumCards; + player->opl.AdlBank = midi_device->AdlBank; + player->opl.NumFourOps = midi_device->NumFourOps; + player->opl.LogarithmicVolumes = (bool)midi_device->LogarithmicVolumes; + player->opl.HighTremoloMode = (bool)midi_device->HighTremoloMode; + player->opl.HighVibratoMode = (bool)midi_device->HighVibratoMode; + player->opl.AdlPercussionMode = (bool)midi_device->AdlPercussionMode; + player->opl.ScaleModulators = (bool)midi_device->ScaleModulators; player->ChooseDevice("none"); - adlRefreshNumCards(_device); - return _device; + adlRefreshNumCards(midi_device); + return midi_device; } ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards) @@ -92,6 +87,12 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards) ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) { + #ifdef DISABLE_EMBEDDED_BANKS + ADL_UNUSED(device); + ADL_UNUSED(bank); + ADLMIDI_ErrorString = "This build of libADLMIDI has no embedded banks. Please load bank by using of adl_openBankFile() or adl_openBankData() functions instead of adl_setBank()"; + return -1; + #else const uint32_t NumBanks = static_cast<uint32_t>(maxAdlBanks()); int32_t bankno = bank; @@ -99,7 +100,8 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) bankno = 0; device->AdlBank = static_cast<uint32_t>(bankno); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.AdlBank = device->AdlBank; + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->opl.AdlBank = device->AdlBank; if(device->AdlBank >= NumBanks) { @@ -110,6 +112,7 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) } return adlRefreshNumCards(device); + #endif } ADLMIDI_EXPORT int adl_getBanksCount() @@ -317,6 +320,14 @@ ADLMIDI_EXPORT void adl_reset(ADL_MIDIPlayer *device) reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.Reset(); } +ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) +{ + if(!device) + return; + reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->rewind(); +} + + #ifdef ADLMIDI_USE_DOSBOX_OPL #define ADLMIDI_CLAMP(V, MIN, MAX) std::max(std::min(V, (MAX)), (MIN)) @@ -393,9 +404,6 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) if(sampleCount < 0) return 0; - if(device->QuitFlag) - return 0; - ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; //ssize_t n_periodCountPhys = n_periodCountStereo * 2; @@ -446,6 +454,9 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) out_buf.resize(1024 /*n_samples * 2*/); MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + if((player->atEnd) && (device->delay <= 0.0)) + break;//Stop to fetch samples at reaching of song end with disabled loop + ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; ssize_t in_generatedPhys = in_generatedStereo * 2; @@ -500,185 +511,3 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) return static_cast<int>(gotten_len); } - -#ifdef ADLMIDI_buildAsApp -static std::deque<short> AudioBuffer; -static MutexType AudioBuffer_lock; - -static void SDL_AudioCallbackX(void *, Uint8 *stream, int len) -{ - SDL_LockAudio(); - short *target = (short *) stream; - AudioBuffer_lock.Lock(); - /*if(len != AudioBuffer.size()) - fprintf(stderr, "len=%d stereo samples, AudioBuffer has %u stereo samples", - len/4, (unsigned) AudioBuffer.size()/2);*/ - unsigned ate = len / 2; // number of shorts - - if(ate > AudioBuffer.size()) ate = AudioBuffer.size(); - - for(unsigned a = 0; a < ate; ++a) - target[a] = AudioBuffer[a]; - - AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin() + ate); - AudioBuffer_lock.Unlock(); - SDL_UnlockAudio(); -} - -int main(int argc, char **argv) -{ - if(argc < 2 || std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h") - { - std::printf( - "Usage: adlmidi <midifilename> [ <options> ] [ <banknumber> [ <numcards> [ <numfourops>] ] ]\n" - " -p Enables adlib percussion instrument mode\n" - " -t Enables tremolo amplification mode\n" - " -v Enables vibrato amplification mode\n" - " -s Enables scaling of modulator volumes\n" - " -nl Quit without looping\n" - " -w Write WAV file rather than playing\n" - ); - - for(unsigned a = 0; a < sizeof(banknames) / sizeof(*banknames); ++a) - std::printf("%10s%2u = %s\n", - a ? "" : "Banks:", - a, - banknames[a]); - - std::printf( - " Use banks 2-5 to play Descent \"q\" soundtracks.\n" - " Look up the relevant bank number from descent.sng.\n" - "\n" - " The fourth parameter can be used to specify the number\n" - " of four-op channels to use. Each four-op channel eats\n" - " the room of two regular channels. Use as many as required.\n" - " The Doom & Hexen sets require one or two, while\n" - " Miles four-op set requires the maximum of numcards*6.\n" - "\n" - ); - return 0; - } - - //const unsigned MaxSamplesAtTime = 512; // 512=dbopl limitation - // How long is SDL buffer, in seconds? - // The smaller the value, the more often SDL_AudioCallBack() - // is called. - const double AudioBufferLength = 0.08; - // How much do WE buffer, in seconds? The smaller the value, - // the more prone to sound chopping we are. - const double OurHeadRoomLength = 0.1; - // The lag between visual content and audio content equals - // the sum of these two buffers. - SDL_AudioSpec spec; - SDL_AudioSpec obtained; - spec.freq = 44100; - spec.format = AUDIO_S16SYS; - spec.channels = 2; - spec.samples = spec.freq * AudioBufferLength; - spec.callback = SDL_AudioCallbackX; - - // Set up SDL - if(SDL_OpenAudio(&spec, &obtained) < 0) - { - std::fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); - //return 1; - } - - if(spec.samples != obtained.samples) - std::fprintf(stderr, "Wanted (samples=%u,rate=%u,channels=%u); obtained (samples=%u,rate=%u,channels=%u)\n", - spec.samples, spec.freq, spec.channels, - obtained.samples, obtained.freq, obtained.channels); - - ADL_MIDIPlayer *myDevice; - myDevice = adl_init(44100); - - if(myDevice == NULL) - { - std::fprintf(stderr, "Failed to init MIDI device!\n"); - return 1; - } - - while(argc > 2) - { - bool had_option = false; - - if(!std::strcmp("-p", argv[2])) - adl_setPercMode(myDevice, 1); - else if(!std::strcmp("-v", argv[2])) - adl_setHVibrato(myDevice, 1); - else if(!std::strcmp("-t", argv[2])) - adl_setHTremolo(myDevice, 1); - else if(!std::strcmp("-nl", argv[2])) - adl_setLoopEnabled(myDevice, 0); - else if(!std::strcmp("-s", argv[2])) - adl_setScaleModulators(myDevice, 1); - else break; - - std::copy(argv + (had_option ? 4 : 3), argv + argc, - argv + 2); - argc -= (had_option ? 2 : 1); - } - - if(argc >= 3) - { - int bankno = std::atoi(argv[2]); - - if(adl_setBank(myDevice, bankno) != 0) - { - std::fprintf(stderr, "%s", adl_errorString()); - return 0; - } - } - - if(argc >= 4) - { - if(adl_setNumCards(myDevice, std::atoi(argv[3])) != 0) - { - std::fprintf(stderr, "%s\n", adl_errorString()); - return 0; - } - } - - if(argc >= 5) - { - if(adl_setNumFourOpsChn(myDevice, std::atoi(argv[4])) != 0) - { - std::fprintf(stderr, "%s\n", adl_errorString()); - return 0; - } - } - - if(adl_openFile(myDevice, argv[1]) != 0) - { - std::fprintf(stderr, "%s\n", adl_errorString()); - return 2; - } - - SDL_PauseAudio(0); - - while(1) - { - int buff[4096]; - unsigned long gotten = adl_play(myDevice, 4096, buff); - - if(gotten <= 0) break; - - AudioBuffer_lock.Lock(); - size_t pos = AudioBuffer.size(); - AudioBuffer.resize(pos + gotten); - - for(unsigned long p = 0; p < gotten; ++p) - AudioBuffer[pos + p] = buff[p]; - - AudioBuffer_lock.Unlock(); - const SDL_AudioSpec &spec_ = obtained; - - while(AudioBuffer.size() > spec_.samples + (spec_.freq * 2) * OurHeadRoomLength) - SDL_Delay(1); - } - - adl_close(myDevice); - SDL_CloseAudio(); - return 0; -} -#endif |