diff options
author | Wohlstand <admin@wohlnet.ru> | 2024-05-11 00:00:33 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2024-05-11 00:00:33 +0300 |
commit | 63141d11132fedfd63860fc42e16de1f48312e01 (patch) | |
tree | 1f264994af81ece8bb1d78c5313d7818c64ff883 /utils/midiplay | |
parent | 759de2665f6cfecffc074c48b5caa56b7a1d1deb (diff) | |
download | libADLMIDI-63141d11132fedfd63860fc42e16de1f48312e01.tar.gz libADLMIDI-63141d11132fedfd63860fc42e16de1f48312e01.tar.bz2 libADLMIDI-63141d11132fedfd63860fc42e16de1f48312e01.zip |
Initial implementation of Serial support
+ refactor of the MIDI play, making separated loop functions instead the mess of everything in one single loop function.
Diffstat (limited to 'utils/midiplay')
-rw-r--r-- | utils/midiplay/adlmidiplay.cpp | 965 |
1 files changed, 616 insertions, 349 deletions
diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp index fe0a758..07b0ffc 100644 --- a/utils/midiplay/adlmidiplay.cpp +++ b/utils/midiplay/adlmidiplay.cpp @@ -35,6 +35,10 @@ #include <signal.h> #include <stdint.h> +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) +# include <time.h> +#endif + #ifdef DEBUG_SONG_SWITCHING #include <unistd.h> #include <sys/select.h> @@ -439,6 +443,534 @@ static inline void secondsToHMSM(double seconds_full, char *hmsm_buffer, size_t snprintf(hmsm_buffer, hmsm_buffer_size, "%02u:%02u,%03u", minutes, seconds, milliseconds); } + +static struct TimeCounter +{ + char posHMS[25]; + char totalHMS[25]; + char loopStartHMS[25]; + char loopEndHMS[25]; + + bool hasLoop; + uint64_t milliseconds_prev; + int printsCounter; + int printsCounterPeriod; + int complete_prev; + double totalTime; + +#ifdef HARDWARE_OPL3 + unsigned newTimerFreq; + unsigned timerPeriod; + int haveYield; + unsigned long BIOStimer_begin; +#endif + + TimeCounter() + { + hasLoop = false; + totalTime = 0.0; + milliseconds_prev = ~0u; + printsCounter = 0; + complete_prev = -1; + +#ifndef HARDWARE_OPL3 + printsCounterPeriod = 1; +#else + printsCounterPeriod = 20; + setDosTimerHZ(209); + haveYield = 0; +#endif + } + +#ifdef HARDWARE_OPL3 + void initDosTimer() + { +# ifdef __DJGPP__ + errno = 0; + __dpmi_yield(); + haveYield = errno ? 0 : 1; + + if(!haveYield) + std::fprintf(stdout, " - [DOS] dmpi_yield failed, using hlt\n"); +# endif + } + + void setDosTimerHZ(unsigned timer) + { + newTimerFreq = timer; + timerPeriod = 0x1234DDul / newTimerFreq; + } + + void flushDosTimer() + { +# ifdef __DJGPP__ + outportb(0x43, 0x34); + outportb(0x40, timerPeriod & 0xFF); + outportb(0x40, timerPeriod >> 8); +# endif + +# ifdef __WATCOMC__ + outp(0x43, 0x34); + outp(0x40, TimerPeriod & 0xFF); + outp(0x40, TimerPeriod >> 8); +# endif + + BIOStimer_begin = BIOStimer; + + std::fprintf(stdout, " - [DOS] Running clock with %d hz\n", newTimerFreq); + } + + void restoreDosTimer() + { +# ifdef __DJGPP__ + // Fix the skewed clock and reset BIOS tick rate + _farpokel(_dos_ds, 0x46C, BIOStimer_begin + (BIOStimer - BIOStimer_begin) * (0x1234DD / 65536.0) / newTimerFreq); + + //disable(); + outportb(0x43, 0x34); + outportb(0x40, 0); + outportb(0x40, 0); + //enable(); +# endif + +# ifdef __WATCOMC__ + outp(0x43, 0x34); + outp(0x40, 0); + outp(0x40, 0); +# endif + } + + void waitDosTimer() + { +//__asm__ volatile("sti\nhlt"); +//usleep(10000); +# ifdef __DJGPP__ + if(haveYield) + __dpmi_yield(); + else + __asm__ volatile("hlt"); +# endif +# ifdef __WATCOMC__ + //dpmi_dos_yield(); + mch_delay((unsigned int)(tick_delay * 1000.0)); +# endif + } +#endif + + void setTotal(double total) + { + totalTime = total; + secondsToHMSM(total, totalHMS, 25); + } + + void setLoop(double loopStart, double loopEnd) + { + hasLoop = false; + + if(loopStart >= 0.0 && loopEnd >= 0.0) + { + secondsToHMSM(loopStart, loopStartHMS, 25); + secondsToHMSM(loopEnd, loopEndHMS, 25); + hasLoop = true; + } + } + + void clearLineR() + { + std::fprintf(stdout, " \r"); + flushout(stdout); + } + + void printTime(double pos) + { + uint64_t milliseconds = static_cast<uint64_t>(pos * 1000.0); + + if(milliseconds != milliseconds_prev) + { + if(printsCounter >= printsCounterPeriod) + { + printsCounter = -1; + secondsToHMSM(pos, posHMS, 25); + std::fprintf(stdout, " \r"); + std::fprintf(stdout, "Time position: %s / %s\r", posHMS, totalHMS); + flushout(stdout); + milliseconds_prev = milliseconds; + } + printsCounter++; + } + } + + void printProgress(double pos) + { + int complete = static_cast<int>(std::floor(100.0 * pos / totalTime)); + + if(complete_prev != complete) + { + std::fprintf(stdout, " \r"); + std::fprintf(stdout, "Recording WAV... [%d%% completed]\r", complete); + flushout(stdout); + complete_prev = complete; + } + } + + void clearLine() + { + std::fprintf(stdout, " \n\n"); + flushout(stdout); + } + +} s_timeCounter; + + + +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) +static void runHWSerialLoop(ADL_MIDIPlayer *myDevice) +{ + double tick_delay = 0.00000001; + double tick_wait = 0.0; + struct timespec timerBeg, timerEnd; + long long timeBegL, timeEndL; + const double minDelay = 0.005; + double eat_delay; + bool tickSkip = true; + + s_timeCounter.clearLineR(); + + while(!stop) + { + clock_gettime(CLOCK_REALTIME, &timerBeg); + + tick_delay = adl_tickEventsOnly(myDevice, tick_delay, 0.000000001); + adl_tickIterators(myDevice, tick_delay < minDelay ? tick_delay : minDelay); + + if(adl_atEnd(myDevice) && tick_delay <= 0) + stop = true; + +# ifndef DEBUG_TRACE_ALL_EVENTS + s_timeCounter.printTime(adl_positionTell(myDevice)); +# endif + + clock_gettime(CLOCK_REALTIME, &timerEnd); + + if(tick_delay < 0.00000001) + tick_delay = 0.00000001; + + timeBegL = timerBeg.tv_nsec + (timerBeg.tv_sec * 1000000000); + timeEndL = timerEnd.tv_nsec + (timerEnd.tv_sec * 1000000000); + + eat_delay = (double)(timeEndL - timeBegL) / 1000000000; + tick_wait += tick_delay - eat_delay; + + if(tick_wait > 0.0) + { + if(tick_wait < minDelay) + { + usleep(tick_wait * 1000000); + tick_wait = 0.0; + } + + while(tick_wait > 0.0) + { + clock_gettime(CLOCK_REALTIME, &timerBeg); + if(!tickSkip) + adl_tickIterators(myDevice, minDelay); + else + tickSkip = false; + clock_gettime(CLOCK_REALTIME, &timerEnd); + + timeBegL = timerBeg.tv_nsec + (timerBeg.tv_sec * 1000000000); + timeEndL = timerEnd.tv_nsec + (timerEnd.tv_sec * 1000000000); + + double microDelay = minDelay - ((timeEndL - timeBegL) / 1000000000.0); + + if(microDelay > 0.0) + usleep(microDelay * 1000000); + + tick_wait -= minDelay; + } + } + } + + s_timeCounter.clearLine(); + + adl_panic(myDevice); //Shut up all sustaining notes +} +#endif // ADLMIDI_ENABLE_HW_SERIAL + + +#ifndef HARDWARE_OPL3 +# ifndef OUTPUT_WAVE_ONLY +static int runAudioLoop(ADL_MIDIPlayer *myDevice, AudioOutputSpec &spec) +{ + //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. + + AudioOutputSpec obtained; + + // Set up SDL + if(audio_init(&spec, &obtained, SDL_AudioCallbackX) < 0) + { + std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", audio_get_error()); + return 1; + } + + if(spec.samples != obtained.samples) + { + std::fprintf(stderr, " - Audio wanted (format=%s,samples=%u,rate=%u,channels=%u);\n" + " - Audio obtained (format=%s,samples=%u,rate=%u,channels=%u)\n", + audio_format_to_str(spec.format, spec.is_msb), spec.samples, spec.freq, spec.channels, + audio_format_to_str(obtained.format, obtained.is_msb), obtained.samples, obtained.freq, obtained.channels); + } + + switch(obtained.format) + { + case ADLMIDI_SampleType_S8: + g_audioFormat.type = ADLMIDI_SampleType_S8; + g_audioFormat.containerSize = sizeof(int8_t); + g_audioFormat.sampleOffset = sizeof(int8_t) * 2; + break; + case ADLMIDI_SampleType_U8: + g_audioFormat.type = ADLMIDI_SampleType_U8; + g_audioFormat.containerSize = sizeof(uint8_t); + g_audioFormat.sampleOffset = sizeof(uint8_t) * 2; + break; + case ADLMIDI_SampleType_S16: + g_audioFormat.type = ADLMIDI_SampleType_S16; + g_audioFormat.containerSize = sizeof(int16_t); + g_audioFormat.sampleOffset = sizeof(int16_t) * 2; + break; + case ADLMIDI_SampleType_U16: + g_audioFormat.type = ADLMIDI_SampleType_U16; + g_audioFormat.containerSize = sizeof(uint16_t); + g_audioFormat.sampleOffset = sizeof(uint16_t) * 2; + break; + case ADLMIDI_SampleType_S32: + g_audioFormat.type = ADLMIDI_SampleType_S32; + g_audioFormat.containerSize = sizeof(int32_t); + g_audioFormat.sampleOffset = sizeof(int32_t) * 2; + break; + case ADLMIDI_SampleType_F32: + g_audioFormat.type = ADLMIDI_SampleType_F32; + g_audioFormat.containerSize = sizeof(float); + g_audioFormat.sampleOffset = sizeof(float) * 2; + break; + } + + +# ifdef DEBUG_SONG_CHANGE + int delayBeforeSongChange = 50; + std::fprintf(stdout, "DEBUG: === Random song set test is active! ===\n"); + flushout(stdout); +# endif + +# ifdef DEBUG_SEEKING_TEST + int delayBeforeSeek = 50; + std::fprintf(stdout, "DEBUG: === Random position set test is active! ===\n"); + flushout(stdout); +# endif + + size_t got; + uint8_t buff[16384]; + + audio_start(); + + s_timeCounter.clearLineR(); + + while(!stop) + { + got = (size_t)adl_playFormat(myDevice, 4096, + buff, + buff + g_audioFormat.containerSize, + &g_audioFormat) * g_audioFormat.containerSize; + if(got <= 0) + break; + +# ifdef DEBUG_TRACE_ALL_CHANNELS + enum { TerminalColumns = 80 }; + char channelText[TerminalColumns + 1]; + char channelAttr[TerminalColumns + 1]; + adl_describeChannels(myDevice, channelText, channelAttr, sizeof(channelText)); + std::fprintf(stdout, "%*s\r", TerminalColumns, ""); // erase the line + std::fprintf(stdout, "%s\n", channelText); +# endif + +# ifndef DEBUG_TRACE_ALL_EVENTS + s_timeCounter.printTime(adl_positionTell(myDevice)); +# endif + + g_audioBuffer_lock.Lock(); + size_t pos = g_audioBuffer.size(); + g_audioBuffer.resize(pos + got); + for(size_t p = 0; p < got; ++p) + g_audioBuffer[pos + p] = buff[p]; + g_audioBuffer_lock.Unlock(); + + const AudioOutputSpec &spec = obtained; + while(!stop && (g_audioBuffer.size() > static_cast<size_t>(spec.samples + (spec.freq * g_audioFormat.sampleOffset) * OurHeadRoomLength))) + { + audio_delay(1); + } + +# ifdef DEBUG_SONG_SWITCHING + if(kbhit()) + { + int code = getch(); + if(code == '\033' && kbhit()) + { + getch(); + switch(getch()) + { + case 'C': + // code for arrow right + songNumLoad++; + if(songNumLoad >= songsCount) + songNumLoad = songsCount; + adl_selectSongNum(myDevice, songNumLoad); + std::fprintf(stdout, "\rSwitching song to %d/%d... \r\n", songNumLoad, songsCount); + flushout(stdout); + break; + case 'D': + // code for arrow left + songNumLoad--; + if(songNumLoad < 0) + songNumLoad = 0; + adl_selectSongNum(myDevice, songNumLoad); + std::fprintf(stdout, "\rSwitching song to %d/%d... \r\n", songNumLoad, songsCount); + flushout(stdout); + break; + } + } + else if(code == 27) // Quit by ESC key + stop = 1; + } +# endif + +# ifdef DEBUG_SEEKING_TEST + if(delayBeforeSeek-- <= 0) + { + delayBeforeSeek = rand() % 50; + double seekTo = double((rand() % int(adl_totalTimeLength(myDevice)) - delayBeforeSeek - 1 )); + adl_positionSeek(myDevice, seekTo); + } +# endif + +# ifdef DEBUG_SONG_CHANGE + if(delayBeforeSongChange-- <= 0) + { + delayBeforeSongChange = rand() % 100; + adl_selectSongNum(myDevice, rand() % 10); + } +# endif + +# ifdef DEBUG_SONG_CHANGE_BY_HOOK + if(gotXmiTrigger) + { + gotXmiTrigger = false; + adl_selectSongNum(myDevice, (rand() % 10) + 1); + } +# endif + } + + s_timeCounter.clearLine(); + + audio_stop(); + audio_close(); + + return 0; +} +# endif // OUTPUT_WAVE_ONLY + +static int runWaveOutLoopLoop(ADL_MIDIPlayer *myDevice, const std::string &musPath, unsigned sampleRate) +{ + std::string wave_out = musPath + ".wav"; + std::fprintf(stdout, " - Recording WAV file %s...\n", wave_out.c_str()); + std::fprintf(stdout, "\n==========================================\n"); + flushout(stdout); + + if(wave_open(static_cast<long>(sampleRate), wave_out.c_str()) == 0) + { + wave_enable_stereo(); + short buff[4096]; + + while(!stop) + { + size_t got = static_cast<size_t>(adl_play(myDevice, 4096, buff)); + if(got <= 0) + break; + wave_write(buff, static_cast<long>(got)); + + s_timeCounter.printProgress(adl_positionTell(myDevice)); + } + + wave_close(); + s_timeCounter.clearLine(); + + if(stop) + std::fprintf(stdout, "Interrupted! Recorded WAV is incomplete, but playable!\n"); + else + std::fprintf(stdout, "Completed!\n"); + flushout(stdout); + } + else + { + adl_close(myDevice); + return 1; + } + + return 0; +} + +#else // HARDWARE_OPL3 +static void runDOSLoop(ADL_MIDIPlayer *myDevice) +{ + double tick_delay = 0.0; + + s_timeCounter.clearLineR(); + + while(!stop) + { + const double mindelay = 1.0 / s_timeCounter.newTimerFreq; + +# ifndef DEBUG_TRACE_ALL_EVENTS + s_timeCounter.printTime(adl_positionTell(myDevice)); +# endif + + s_timeCounter.waitDosTimer(); + + static unsigned long PrevTimer = BIOStimer; + const unsigned long CurTimer = BIOStimer; + const double eat_delay = (CurTimer - PrevTimer) / (double)s_timeCounter.newTimerFreq; + PrevTimer = CurTimer; + + tick_delay = adl_tickEvents(myDevice, eat_delay, mindelay); + + if(adl_atEnd(myDevice) && tick_delay <= 0) + stop = true; + + if(kbhit()) + { // Quit on ESC key! + int c = getch(); + if(c == 27) + stop = true; + } + } + + s_timeCounter.clearLine(); + + adl_panic(myDevice); //Shut up all sustaining notes +} +#endif // HARDWARE_OPL3 + + int main(int argc, char **argv) { std::fprintf(stdout, "==========================================\n" @@ -519,36 +1051,28 @@ int main(int argc, char **argv) } unsigned int sampleRate = 44100; -#ifndef HARDWARE_OPL3 +#if !defined(HARDWARE_OPL3) && !defined(OUTPUT_WAVE_ONLY) //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. -# ifndef OUTPUT_WAVE_ONLY AudioOutputSpec spec; - AudioOutputSpec obtained; - spec.freq = sampleRate; spec.format = ADLMIDI_SampleType_S16; spec.is_msb = 0; spec.channels = 2; spec.samples = uint16_t((double)spec.freq * AudioBufferLength); -# endif //OUTPUT_WAVE_ONLY -#endif //HARDWARE_OPL3 +#endif // !HARDWARE_OPL3 && !OUTPUT_WAVE_ONLY -#ifdef HARDWARE_OPL3 - static unsigned newTimerFreq = 209; - unsigned timerPeriod = 0x1234DDul / newTimerFreq; +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) + bool hwSerial = false; + std::string serialName; + unsigned serialBaud = 115200; + unsigned serialProto = ADLMIDI_SerialProtocol_RetroWaveOPL3; #endif - ADL_MIDIPlayer *myDevice; //Initialize libADLMIDI and create the instance (you can initialize multiple of them!) @@ -648,6 +1172,39 @@ int main(int argc, char **argv) else if(!std::strcmp("--emu-java", argv[2])) emulator = ADLMIDI_EMU_JAVA; #endif +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) + else if(!std::strcmp("--serial", argv[2])) + { + if(argc <= 3) + { + printError("The option --serial requires an argument!\n"); + return 1; + } + had_option = true; + hwSerial = true; + serialName = argv[3]; + } + else if(!std::strcmp("--serial-baud", argv[2])) + { + if(argc <= 3) + { + printError("The option --serial-baud requires an argument!\n"); + return 1; + } + had_option = true; + serialBaud = std::strtol(argv[3], NULL, 10); + } + else if(!std::strcmp("--serial-proto", argv[2])) + { + if(argc <= 3) + { + printError("The option --serial-proto requires an argument!\n"); + return 1; + } + had_option = true; + serialProto = std::strtol(argv[3], NULL, 10); + } +#endif else if(!std::strcmp("-fp", argv[2])) adl_setSoftPanEnabled(myDevice, 1); else if(!std::strcmp("-mb", argv[2])) @@ -663,14 +1220,15 @@ int main(int argc, char **argv) printError("The option --time-freq requires an argument!\n"); return 1; } - newTimerFreq = std::strtoul(argv[3], NULL, 0); - if(newTimerFreq == 0) + + unsigned timerFreq = std::strtoul(argv[3], NULL, 0); + if(timerFreq == 0) { printError("The option --time-freq requires a non-zero integer argument!\n"); return 1; } - timerPeriod = 0x1234DDul / newTimerFreq; + s_timeCounter.setDosTimerHZ(timerFreq); had_option = true; } @@ -763,6 +1321,11 @@ int main(int argc, char **argv) adl_setRawEventHook(myDevice, debugPrintEvent, NULL); #endif +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) + if(hwSerial) + adl_switchSerialHW(myDevice, serialName.c_str(), serialBaud, serialProto); + else +#endif #ifndef HARDWARE_OPL3 adl_switchEmulator(myDevice, emulator); #endif @@ -770,65 +1333,15 @@ int main(int argc, char **argv) std::fprintf(stdout, " - Library version %s\n", adl_linkedLibraryVersion()); #ifdef HARDWARE_OPL3 std::fprintf(stdout, " - Hardware OPL3 chip in use\n"); +#elif defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) + if(hwSerial) + std::fprintf(stdout, " - %s [device %s] in use\n", adl_chipEmulatorName(myDevice), serialName.c_str()); + else + std::fprintf(stdout, " - %s Emulator in use\n", adl_chipEmulatorName(myDevice)); #else std::fprintf(stdout, " - %s Emulator in use\n", adl_chipEmulatorName(myDevice)); #endif -#if !defined(HARDWARE_OPL3) && !defined(OUTPUT_WAVE_ONLY) - if(!recordWave) - { - // Set up SDL - if(audio_init(&spec, &obtained, SDL_AudioCallbackX) < 0) - { - std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", audio_get_error()); - adl_close(myDevice); - return 1; - } - - if(spec.samples != obtained.samples) - { - std::fprintf(stderr, " - Audio wanted (format=%s,samples=%u,rate=%u,channels=%u);\n" - " - Audio obtained (format=%s,samples=%u,rate=%u,channels=%u)\n", - audio_format_to_str(spec.format, spec.is_msb), spec.samples, spec.freq, spec.channels, - audio_format_to_str(obtained.format, obtained.is_msb), obtained.samples, obtained.freq, obtained.channels); - } - - switch(obtained.format) - { - case ADLMIDI_SampleType_S8: - g_audioFormat.type = ADLMIDI_SampleType_S8; - g_audioFormat.containerSize = sizeof(int8_t); - g_audioFormat.sampleOffset = sizeof(int8_t) * 2; - break; - case ADLMIDI_SampleType_U8: - g_audioFormat.type = ADLMIDI_SampleType_U8; - g_audioFormat.containerSize = sizeof(uint8_t); - g_audioFormat.sampleOffset = sizeof(uint8_t) * 2; - break; - case ADLMIDI_SampleType_S16: - g_audioFormat.type = ADLMIDI_SampleType_S16; - g_audioFormat.containerSize = sizeof(int16_t); - g_audioFormat.sampleOffset = sizeof(int16_t) * 2; - break; - case ADLMIDI_SampleType_U16: - g_audioFormat.type = ADLMIDI_SampleType_U16; - g_audioFormat.containerSize = sizeof(uint16_t); - g_audioFormat.sampleOffset = sizeof(uint16_t) * 2; - break; - case ADLMIDI_SampleType_S32: - g_audioFormat.type = ADLMIDI_SampleType_S32; - g_audioFormat.containerSize = sizeof(int32_t); - g_audioFormat.sampleOffset = sizeof(int32_t) * 2; - break; - case ADLMIDI_SampleType_F32: - g_audioFormat.type = ADLMIDI_SampleType_F32; - g_audioFormat.containerSize = sizeof(float); - g_audioFormat.sampleOffset = sizeof(float) * 2; - break; - } - } -#endif - if(argc >= 3) { if(is_number(argv[2])) @@ -902,6 +1415,11 @@ int main(int argc, char **argv) if(argc >= 4) numOfChips = std::atoi(argv[3]); +#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) + if(hwSerial) + numOfChips = 1; +#endif + //Set count of concurrent emulated chips count to excite channels limit of one chip if(adl_setNumChips(myDevice, numOfChips) != 0) { @@ -933,6 +1451,7 @@ int main(int argc, char **argv) adl_setLoopEndHook(myDevice, loopEndCallback, NULL); adl_setLoopHooksOnly(myDevice, 1); #endif + if(songNumLoad >= 0) adl_selectSongNum(myDevice, songNumLoad); @@ -947,6 +1466,7 @@ int main(int argc, char **argv) if(adl_openFile(myDevice, musPath.c_str()) != 0) { printError(adl_errorInfo(myDevice)); + adl_close(myDevice); return 2; } @@ -996,242 +1516,46 @@ int main(int argc, char **argv) # endif #else // HARDWARE_OPL3 - -# ifdef __DJGPP__ - //disable(); - errno = 0; - __dpmi_yield(); - int haveYield = errno ? 0 : 1; - - if(!haveYield) - std::fprintf(stdout, " - [DOS] dmpi_yield failed, using hlt\n"); - - outportb(0x43, 0x34); - outportb(0x40, timerPeriod & 0xFF); - outportb(0x40, timerPeriod >> 8); - std::fprintf(stdout, " - [DOS] Running clock with %d hz\n", newTimerFreq); - //enable(); -# endif//__DJGPP__ - -# ifdef __WATCOMC__ - std::fprintf(stdout, " - Initializing BIOS timer...\n"); - flushout(stdout); //disable(); - outp(0x43, 0x34); - outp(0x40, TimerPeriod & 0xFF); - outp(0x40, TimerPeriod >> 8); + s_timeCounter.initDosTimer(); + s_timeCounter.flushDosTimer(); //enable(); - std::fprintf(stdout, " - Ok!\n"); - flushout(stdout); -# endif//__WATCOMC__ - - unsigned long BIOStimer_begin = BIOStimer; - double tick_delay = 0.0; #endif//HARDWARE_OPL3 - double total = adl_totalTimeLength(myDevice); + s_timeCounter.setTotal(adl_totalTimeLength(myDevice)); #ifndef OUTPUT_WAVE_ONLY - double loopStart = adl_loopStartTime(myDevice); - double loopEnd = adl_loopEndTime(myDevice); - char totalHMS[25]; - char loopStartHMS[25]; - char loopEndHMS[25]; - secondsToHMSM(total, totalHMS, 25); - if(loopStart >= 0.0 && loopEnd >= 0.0) - { - secondsToHMSM(loopStart, loopStartHMS, 25); - secondsToHMSM(loopEnd, loopEndHMS, 25); - } + s_timeCounter.setLoop(adl_loopStartTime(myDevice), adl_loopEndTime(myDevice)); # ifndef HARDWARE_OPL3 if(!recordWave) # endif { std::fprintf(stdout, " - Loop is turned %s\n", loopEnabled ? "ON" : "OFF"); - if(loopStart >= 0.0 && loopEnd >= 0.0) - std::fprintf(stdout, " - Has loop points: %s ... %s\n", loopStartHMS, loopEndHMS); + if(s_timeCounter.hasLoop) + std::fprintf(stdout, " - Has loop points: %s ... %s\n", s_timeCounter.loopStartHMS, s_timeCounter.loopEndHMS); std::fprintf(stdout, "\n==========================================\n"); flushout(stdout); # ifndef HARDWARE_OPL3 - audio_start(); -# endif - -# ifdef DEBUG_SONG_CHANGE - int delayBeforeSongChange = 50; - std::fprintf(stdout, "DEBUG: === Random song set test is active! ===\n"); - flushout(stdout); -# endif - -# ifdef DEBUG_SEEKING_TEST - int delayBeforeSeek = 50; - std::fprintf(stdout, "DEBUG: === Random position set test is active! ===\n"); - flushout(stdout); -# endif - -# ifndef HARDWARE_OPL3 - uint8_t buff[16384]; -# endif - char posHMS[25]; - uint64_t milliseconds_prev = ~0u; - int printsCounter = 0; - int printsCounterPeriod = 1; -# ifdef HARDWARE_OPL3 - printsCounterPeriod = 500; -# endif - - std::fprintf(stdout, " \r"); - - while(!stop) - { -# ifndef HARDWARE_OPL3 - size_t got = (size_t)adl_playFormat(myDevice, 4096, - buff, - buff + g_audioFormat.containerSize, - &g_audioFormat) * g_audioFormat.containerSize; - if(got <= 0) - break; -# endif - -# ifdef DEBUG_TRACE_ALL_CHANNELS - enum { TerminalColumns = 80 }; - char channelText[TerminalColumns + 1]; - char channelAttr[TerminalColumns + 1]; - adl_describeChannels(myDevice, channelText, channelAttr, sizeof(channelText)); - std::fprintf(stdout, "%*s\r", TerminalColumns, ""); // erase the line - std::fprintf(stdout, "%s\n", channelText); -# endif - -# ifndef DEBUG_TRACE_ALL_EVENTS - double time_pos = adl_positionTell(myDevice); - uint64_t milliseconds = static_cast<uint64_t>(time_pos * 1000.0); - - if(milliseconds != milliseconds_prev) - { - if(printsCounter >= printsCounterPeriod) - { - printsCounter = -1; - secondsToHMSM(time_pos, posHMS, 25); - std::fprintf(stdout, " \r"); - std::fprintf(stdout, "Time position: %s / %s\r", posHMS, totalHMS); - flushout(stdout); - milliseconds_prev = milliseconds; - } - printsCounter++; - } -# endif - -# ifndef HARDWARE_OPL3 - g_audioBuffer_lock.Lock(); - size_t pos = g_audioBuffer.size(); - g_audioBuffer.resize(pos + got); - for(size_t p = 0; p < got; ++p) - g_audioBuffer[pos + p] = buff[p]; - g_audioBuffer_lock.Unlock(); - - const AudioOutputSpec &spec = obtained; - while(!stop && (g_audioBuffer.size() > static_cast<size_t>(spec.samples + (spec.freq * g_audioFormat.sampleOffset) * OurHeadRoomLength))) - { - audio_delay(1); - } - -# ifdef DEBUG_SONG_SWITCHING - if(kbhit()) - { - int code = getch(); - if(code == '\033' && kbhit()) - { - getch(); - switch(getch()) - { - case 'C': - // code for arrow right - songNumLoad++; - if(songNumLoad >= songsCount) - songNumLoad = songsCount; - adl_selectSongNum(myDevice, songNumLoad); - std::fprintf(stdout, "\rSwitching song to %d/%d... \r\n", songNumLoad, songsCount); - flushout(stdout); - break; - case 'D': - // code for arrow left - songNumLoad--; - if(songNumLoad < 0) - songNumLoad = 0; - adl_selectSongNum(myDevice, songNumLoad); - std::fprintf(stdout, "\rSwitching song to %d/%d... \r\n", songNumLoad, songsCount); - flushout(stdout); - break; - } - } - else if(code == 27) // Quit by ESC key - stop = 1; - } -# endif - -# ifdef DEBUG_SEEKING_TEST - if(delayBeforeSeek-- <= 0) - { - delayBeforeSeek = rand() % 50; - double seekTo = double((rand() % int(adl_totalTimeLength(myDevice)) - delayBeforeSeek - 1 )); - adl_positionSeek(myDevice, seekTo); - } -# endif - -# ifdef DEBUG_SONG_CHANGE - if(delayBeforeSongChange-- <= 0) - { - delayBeforeSongChange = rand() % 100; - adl_selectSongNum(myDevice, rand() % 10); - } +# ifdef ADLMIDI_ENABLE_HW_SERIAL + if(hwSerial) + runHWSerialLoop(myDevice); + else # endif - -# ifdef DEBUG_SONG_CHANGE_BY_HOOK - if(gotXmiTrigger) + { + int ret = runAudioLoop(myDevice, spec); + if (ret != 0) { - gotXmiTrigger = false; - adl_selectSongNum(myDevice, (rand() % 10) + 1); - } -# endif - -# else//HARDWARE_OPL3 - const double mindelay = 1.0 / newTimerFreq; - - //__asm__ volatile("sti\nhlt"); - //usleep(10000); -# ifdef __DJGPP__ - if(haveYield) - __dpmi_yield(); - else - __asm__ volatile("hlt"); -# endif -# ifdef __WATCOMC__ - //dpmi_dos_yield(); - mch_delay((unsigned int)(tick_delay * 1000.0)); -# endif - static unsigned long PrevTimer = BIOStimer; - const unsigned long CurTimer = BIOStimer; - const double eat_delay = (CurTimer - PrevTimer) / (double)newTimerFreq; - PrevTimer = CurTimer; - tick_delay = adl_tickEvents(myDevice, eat_delay, mindelay); - if(adl_atEnd(myDevice) && tick_delay <= 0) - stop = true; - - if(kbhit()) - { // Quit on ESC key! - int c = getch(); - if(c == 27) - stop = true; + adl_close(myDevice); + return ret; } - -# endif//HARDWARE_OPL3 } - std::fprintf(stdout, " \n\n"); -# ifndef HARDWARE_OPL3 - audio_stop(); - audio_close(); +# else + runDOSLoop(myDevice); # endif + + s_timeCounter.clearLine(); } #endif //OUTPUT_WAVE_ONLY @@ -1241,77 +1565,20 @@ int main(int argc, char **argv) else # endif //OUTPUT_WAVE_ONLY { - std::string wave_out = musPath + ".wav"; - std::fprintf(stdout, " - Recording WAV file %s...\n", wave_out.c_str()); - std::fprintf(stdout, "\n==========================================\n"); - flushout(stdout); - - if(wave_open(static_cast<long>(sampleRate), wave_out.c_str()) == 0) - { - wave_enable_stereo(); - short buff[4096]; - int complete_prev = -1; - while(!stop) - { - size_t got = static_cast<size_t>(adl_play(myDevice, 4096, buff)); - if(got <= 0) - break; - wave_write(buff, static_cast<long>(got)); - - int complete = static_cast<int>(std::floor(100.0 * adl_positionTell(myDevice) / total)); - flushout(stdout); - if(complete_prev != complete) - { - std::fprintf(stdout, " \r"); - std::fprintf(stdout, "Recording WAV... [%d%% completed]\r", complete); - std::fflush(stdout); - complete_prev = complete; - } - } - wave_close(); - std::fprintf(stdout, " \n\n"); - - if(stop) - std::fprintf(stdout, "Interrupted! Recorded WAV is incomplete, but playable!\n"); - else - std::fprintf(stdout, "Completed!\n"); - flushout(stdout); - } - else + int ret = runWaveOutLoopLoop(myDevice, musPath, sampleRate); + if(ret != 0) { adl_close(myDevice); - return 1; + return ret; } } #endif //HARDWARE_OPL3 #ifdef HARDWARE_OPL3 - -# ifdef __DJGPP__ - // Fix the skewed clock and reset BIOS tick rate - _farpokel(_dos_ds, 0x46C, BIOStimer_begin + - (BIOStimer - BIOStimer_begin) - * (0x1234DD / 65536.0) / newTimerFreq); - - //disable(); - outportb(0x43, 0x34); - outportb(0x40, 0); - outportb(0x40, 0); - //enable(); -# endif - -# ifdef __WATCOMC__ - outp(0x43, 0x34); - outp(0x40, 0); - outp(0x40, 0); -# endif - - adl_panic(myDevice); //Shut up all sustaining notes - + s_timeCounter.restoreDosTimer(); #endif adl_close(myDevice); return 0; } - |