diff options
author | Wohlstand <admin@wohlnet.ru> | 2017-11-07 01:12:01 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2017-11-07 01:12:01 +0300 |
commit | 22350acc1f699f70cbdac6b5facadd0d6ccc8a7f (patch) | |
tree | fe8f64c337d484f723af25c20fe1e0d264e39e5c /utils/adlmidi-2/midiplay.cc | |
parent | c71f0d4dfe52a523b37416717299700e203f818d (diff) | |
download | libADLMIDI-22350acc1f699f70cbdac6b5facadd0d6ccc8a7f.tar.gz libADLMIDI-22350acc1f699f70cbdac6b5facadd0d6ccc8a7f.tar.bz2 libADLMIDI-22350acc1f699f70cbdac6b5facadd0d6ccc8a7f.zip |
New API, classic ADLMIDI, and CMake
- Attempt to support hardware OPL and add build of classic ADLMIDI into CMake
- Added new API functions
- Added C++ Extras are needed for classic ADLMIDI player
- Error string is no more static. Static variant is kept for initialization errors only.
Diffstat (limited to 'utils/adlmidi-2/midiplay.cc')
-rw-r--r-- | utils/adlmidi-2/midiplay.cc | 480 |
1 files changed, 247 insertions, 233 deletions
diff --git a/utils/adlmidi-2/midiplay.cc b/utils/adlmidi-2/midiplay.cc index bd7c9d6..8ede11b 100644 --- a/utils/adlmidi-2/midiplay.cc +++ b/utils/adlmidi-2/midiplay.cc @@ -8,7 +8,7 @@ #include <set> #include <cstdlib> #include <cstring> -#include <chrono> +#include <ctime> #include <cstdarg> #include <cmath> #include <unistd.h> @@ -21,7 +21,7 @@ #include <assert.h> #define SUPPORT_VIDEO_OUTPUT -//#define SUPPORT_PUZZLE_GAME +#define SUPPORT_PUZZLE_GAME #ifdef __WIN32__ # include <cctype> @@ -35,7 +35,10 @@ typedef unsigned char Uint8; typedef unsigned short Uint16; typedef unsigned Uint32; #else + +#define SDL_MAIN_HANDLED #include <SDL2/SDL.h> + class MutexType { SDL_mutex *mut; @@ -57,13 +60,14 @@ public: #endif #ifdef __DJGPP__ -# include <conio.h> -# include <pc.h> -# include <dpmi.h> -# include <go32.h> -# include <sys/farptr.h> -# include <dos.h> -# define BIOStimer _farpeekl(_dos_ds, 0x46C) +#include <conio.h> +#include <pc.h> +#include <dpmi.h> +#include <go32.h> +#include <sys/farptr.h> +#include <dos.h> +#include <stdlib.h> +#define BIOStimer _farpeekl(_dos_ds, 0x46C) static const unsigned NewTimerFreq = 209; #elif !defined(__WIN32__) || defined(__CYGWIN__) # include <termios.h> @@ -77,16 +81,10 @@ static const unsigned NewTimerFreq = 209; #include <signal.h> - #include "adlmidi.h" -#include "adlmidi_private.hpp" // For OPL3 and MIDIplay classes - -#include "fraction.h" +#include "adlmidi.hpp" #ifndef __DJGPP__ -#include "dbopl.h" - -#include "adldata.hh" static const unsigned long PCM_RATE = 48000; static const unsigned MaxCards = 100; @@ -136,7 +134,7 @@ static void SigWinchHandler(int) {} static void GuessInitialWindowHeight() { - auto s = std::getenv("LINES"); + char *s = std::getenv("LINES"); if(s && std::atoi(s)) WindowLines = (unsigned)std::atoi(s); SigWinchHandler(0); } @@ -438,9 +436,10 @@ public: VidPut(c); ++x; // One letter drawn. Update cursor position. } - #ifdef __DJGPP__ -#define RawPrn cprintf - #else + +#ifdef __DJGPP__ +# define RawPrn cprintf +#else static void RawPrn(const char *fmt, ...) __attribute__((format(printf, 1, 2))) { // Note: should essentially match PutC, except without updates to x @@ -449,7 +448,8 @@ public: vfprintf(stderr, fmt, ap); va_end(ap); } - #endif +#endif + int Print(unsigned beginx, unsigned color, bool ln, const char *fmt, va_list ap) { char Line[1024]; @@ -1270,192 +1270,194 @@ static void SendStereoAudio(unsigned long count, short *samples) /* * THIS CLASS USES !!!ADL PRIVATE!!! */ -class AdlInstrumentTester -{ - uint32_t cur_gm; - uint32_t ins_idx; - std::vector<uint32_t> adl_ins_list; - OPL3 &opl; - -public: - AdlInstrumentTester(OPL3 &o) - : opl(o) - { - cur_gm = 0; - ins_idx = 0; - } - - ~AdlInstrumentTester() - {} - - // Find list of adlib instruments that supposedly implement this GM - void FindAdlList() - { - const unsigned NumBanks = (unsigned)adl_getBanksCount(); - std::set<unsigned> adl_ins_set; - for(unsigned bankno = 0; bankno < NumBanks; ++bankno) - adl_ins_set.insert(banks[bankno][cur_gm]); - adl_ins_list.assign(adl_ins_set.begin(), adl_ins_set.end()); - ins_idx = 0; - NextAdl(0); - opl.Silence(); - } - - - void Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 - { - if(opl.LogarithmicVolumes)// !!!ADL PRIVATE!!! - opl.Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2);// !!!ADL PRIVATE!!! - else - { - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - opl.Touch_Real(c, volume > 8725 ? static_cast<unsigned int>(std::log(volume) * 11.541561 + (0.5 - 104.22845)) : 0);// !!!ADL PRIVATE!!! - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - } - } - - void DoNote(int note) - { - if(adl_ins_list.empty()) FindAdlList(); - const unsigned meta = adl_ins_list[ins_idx]; - const adlinsdata &ains = opl.GetAdlMetaIns(meta);// !!!ADL PRIVATE!!! - - int tone = (cur_gm & 128) ? (cur_gm & 127) : (note + 50); - if(ains.tone) - { - /*if(ains.tone < 20) - tone += ains.tone; - else */ - if(ains.tone < 128) - tone = ains.tone; - else - tone -= ains.tone - 128; - } - double hertz = 172.00093 * std::exp(0.057762265 * (tone + 0.0)); - int i[2] = { ains.adlno1, ains.adlno2 }; - int32_t adlchannel[2] = { 0, 3 }; - if(i[0] == i[1]) - { - adlchannel[1] = -1; - adlchannel[0] = 6; // single-op - std::printf("noteon at %d(%d) for %g Hz\n", - adlchannel[0], i[0], hertz); - } - else - { - std::printf("noteon at %d(%d) and %d(%d) for %g Hz\n", - adlchannel[0], i[0], adlchannel[1], i[1], hertz); - } - - opl.NoteOff(0); - opl.NoteOff(3); - opl.NoteOff(6); - for(unsigned c = 0; c < 2; ++c) - { - if(adlchannel[c] < 0) continue; - opl.Patch((uint16_t)adlchannel[c], (uint16_t)i[c]); - opl.Touch_Real((uint16_t)adlchannel[c], 127 * 127 * 100); - opl.Pan((uint16_t)adlchannel[c], 0x30); - opl.NoteOn((uint16_t)adlchannel[c], hertz); - } - } - - void NextGM(int offset) - { - cur_gm = (cur_gm + 256 + (uint32_t)offset) & 0xFF; - FindAdlList(); - } - - void NextAdl(int offset) - { - if(adl_ins_list.empty()) FindAdlList(); - const unsigned NumBanks = (unsigned)adl_getBanksCount(); - ins_idx = (uint32_t)((int32_t)ins_idx + (int32_t)adl_ins_list.size() + offset) % adl_ins_list.size(); - - UI.Color(15); - std::fflush(stderr); - std::printf("SELECTED G%c%d\t%s\n", - cur_gm < 128 ? 'M' : 'P', cur_gm < 128 ? cur_gm + 1 : cur_gm - 128, - "<-> select GM, ^v select ins, qwe play note"); - std::fflush(stdout); - UI.Color(7); - std::fflush(stderr); - for(unsigned a = 0; a < adl_ins_list.size(); ++a) - { - const unsigned i = adl_ins_list[a]; - const adlinsdata &ains = opl.GetAdlMetaIns(i); - - char ToneIndication[8] = " "; - if(ains.tone) - { - if(ains.tone < 20) - sprintf(ToneIndication, "+%-2d", ains.tone); - else if(ains.tone < 128) - sprintf(ToneIndication, "=%-2d", ains.tone); - else - sprintf(ToneIndication, "-%-2d", ains.tone - 128); - } - std::printf("%s%s%s%u\t", - ToneIndication, - ains.adlno1 != ains.adlno2 ? "[2]" : " ", - (ins_idx == a) ? "->" : "\t", - i - ); - - for(unsigned bankno = 0; bankno < NumBanks; ++bankno) - if(banks[bankno][cur_gm] == i) - std::printf(" %u", bankno); - - std::printf("\n"); - } - } - - void HandleInputChar(char ch) - { - static const char notes[] = "zsxdcvgbhnjmq2w3er5t6y7ui9o0p"; - // c'd'ef'g'a'bC'D'EF'G'A'Bc'd'e - switch(ch) - { - case '/': - case 'H': - case 'A': - NextAdl(-1); - break; - case '*': - case 'P': - case 'B': - NextAdl(+1); - break; - case '-': - case 'K': - case 'D': - NextGM(-1); - break; - case '+': - case 'M': - case 'C': - NextGM(+1); - break; - case 3: - #if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) - case 27: - #endif - QuitFlag = true; - break; - default: - const char *p = strchr(notes, ch); - if(p && *p) DoNote((p - notes) - 12); - } - } - double Tick(double /*eat_delay*/, double /*mindelay*/) - { - HandleInputChar(Input.PeekInput()); - //return eat_delay; - return 0.1; - } -}; +//class OPL3; +//class AdlInstrumentTester +//{ +// uint32_t cur_gm; +// uint32_t ins_idx; +// std::vector<uint32_t> adl_ins_list; +// OPL3 *opl; +// MIDIplay * play; + +//public: +// AdlInstrumentTester(ADL_MIDIPlayer *device) +// { +// cur_gm = 0; +// ins_idx = 0; +// play = reinterpret_cast<MIDIplay*>(device->adl_midiPlayer); +// if(!play) +// return; +// opl = &play->opl; +// } + +// ~AdlInstrumentTester() +// {} + +// // Find list of adlib instruments that supposedly implement this GM +// void FindAdlList() +// { +// const unsigned NumBanks = (unsigned)adl_getBanksCount(); +// std::set<unsigned> adl_ins_set; +// for(unsigned bankno = 0; bankno < NumBanks; ++bankno) +// adl_ins_set.insert(banks[bankno][cur_gm]); +// adl_ins_list.assign(adl_ins_set.begin(), adl_ins_set.end()); +// ins_idx = 0; +// NextAdl(0); +// opl->Silence(); +// } + + +// void Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 +// { +// if(opl->LogarithmicVolumes)// !!!ADL PRIVATE!!! +// opl->Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2);// !!!ADL PRIVATE!!! +// else +// { +// // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) +// opl->Touch_Real(c, volume > 8725 ? static_cast<unsigned int>(std::log(volume) * 11.541561 + (0.5 - 104.22845)) : 0);// !!!ADL PRIVATE!!! +// // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) +// //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); +// } +// } + +// void DoNote(int note) +// { +// if(adl_ins_list.empty()) FindAdlList(); +// const unsigned meta = adl_ins_list[ins_idx]; +// const adlinsdata &ains = opl->GetAdlMetaIns(meta);// !!!ADL PRIVATE!!! + +// int tone = (cur_gm & 128) ? (cur_gm & 127) : (note + 50); +// if(ains.tone) +// { +// /*if(ains.tone < 20) +// tone += ains.tone; +// else */ +// if(ains.tone < 128) +// tone = ains.tone; +// else +// tone -= ains.tone - 128; +// } +// double hertz = 172.00093 * std::exp(0.057762265 * (tone + 0.0)); +// int i[2] = { ains.adlno1, ains.adlno2 }; +// int32_t adlchannel[2] = { 0, 3 }; +// if(i[0] == i[1]) +// { +// adlchannel[1] = -1; +// adlchannel[0] = 6; // single-op +// std::printf("noteon at %d(%d) for %g Hz\n", +// adlchannel[0], i[0], hertz); +// } +// else +// { +// std::printf("noteon at %d(%d) and %d(%d) for %g Hz\n", +// adlchannel[0], i[0], adlchannel[1], i[1], hertz); +// } + +// opl->NoteOff(0); +// opl->NoteOff(3); +// opl->NoteOff(6); +// for(unsigned c = 0; c < 2; ++c) +// { +// if(adlchannel[c] < 0) continue; +// opl->Patch((uint16_t)adlchannel[c], (uint16_t)i[c]); +// opl->Touch_Real((uint16_t)adlchannel[c], 127 * 127 * 100); +// opl->Pan((uint16_t)adlchannel[c], 0x30); +// opl->NoteOn((uint16_t)adlchannel[c], hertz); +// } +// } + +// void NextGM(int offset) +// { +// cur_gm = (cur_gm + 256 + (uint32_t)offset) & 0xFF; +// FindAdlList(); +// } + +// void NextAdl(int offset) +// { +// if(adl_ins_list.empty()) FindAdlList(); +// const unsigned NumBanks = (unsigned)adl_getBanksCount(); +// ins_idx = (uint32_t)((int32_t)ins_idx + (int32_t)adl_ins_list.size() + offset) % adl_ins_list.size(); + +// UI.Color(15); +// std::fflush(stderr); +// std::printf("SELECTED G%c%d\t%s\n", +// cur_gm < 128 ? 'M' : 'P', cur_gm < 128 ? cur_gm + 1 : cur_gm - 128, +// "<-> select GM, ^v select ins, qwe play note"); +// std::fflush(stdout); +// UI.Color(7); +// std::fflush(stderr); +// for(unsigned a = 0; a < adl_ins_list.size(); ++a) +// { +// const unsigned i = adl_ins_list[a]; +// const adlinsdata &ains = opl->GetAdlMetaIns(i); + +// char ToneIndication[8] = " "; +// if(ains.tone) +// { +// /*if(ains.tone < 20) +// std::sprintf(ToneIndication, "+%-2d", ains.tone); +// else*/ +// if(ains.tone < 128) +// std::sprintf(ToneIndication, "=%-2d", ains.tone); +// else +// std::sprintf(ToneIndication, "-%-2d", ains.tone - 128); +// } +// std::printf("%s%s%s%u\t", +// ToneIndication, +// ains.adlno1 != ains.adlno2 ? "[2]" : " ", +// (ins_idx == a) ? "->" : "\t", +// i +// ); + +// for(unsigned bankno = 0; bankno < NumBanks; ++bankno) +// if(banks[bankno][cur_gm] == i) +// std::printf(" %u", bankno); + +// std::printf("\n"); +// } +// } + +// bool HandleInputChar(char ch) +// { +// static const char notes[] = "zsxdcvgbhnjmq2w3er5t6y7ui9o0p"; +// // c'd'ef'g'a'bC'D'EF'G'A'Bc'd'e +// switch(ch) +// { +// case '/': +// case 'H': +// case 'A': +// NextAdl(-1); +// break; +// case '*': +// case 'P': +// case 'B': +// NextAdl(+1); +// break; +// case '-': +// case 'K': +// case 'D': +// NextGM(-1); +// break; +// case '+': +// case 'M': +// case 'C': +// NextGM(+1); +// break; +// case 3: +// #if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) +// case 27: +// #endif +// return false; +// break; +// default: +// const char *p = strchr(notes, ch); +// if(p && *p) +// DoNote((p - notes) - 12); +// } +// return true; +// } +//}; static void TidyupAndExit(int) { @@ -1529,17 +1531,17 @@ static int ParseCommandLine(char *cmdline, char **argv) return(argc); } +extern int main(int argc, char **argv); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) { - extern int main(int, char **); + //extern int main(int, char **); char *cmdline = GetCommandLine(); int argc = ParseCommandLine(cmdline, NULL); char **argv = new char *[argc + 1]; ParseCommandLine(cmdline, argv); -#else -#undef main - - + return main(argc, argv); +} +#endif static void adlEventHook(void *ui, ADL_UInt8 type, ADL_UInt8 subtype, ADL_UInt8 /*channel*/, ADL_UInt8 *data, size_t len) { @@ -1577,7 +1579,6 @@ static void adlDebugMsgHook(void *userdata, const char *fmt, ...) int main(int argc, char **argv) { -#endif // How long is SDL buffer, in seconds? // The smaller the value, the more often AdlAudioCallBack() // is called. @@ -1648,10 +1649,16 @@ int main(int argc, char **argv) return 0; } +#ifndef __DJGPP__ std::srand((unsigned int)std::time(0)); +#endif ADL_MIDIPlayer *myDevice; + #ifndef __DJGPP__ myDevice = adl_init(PCM_RATE); + #else + myDevice = adl_init(48000); + #endif // Set hooks adl_setNoteHook(myDevice, adlNoteHook, (void *)&UI); @@ -1764,6 +1771,7 @@ int main(int argc, char **argv) adl_setBank(myDevice, bankno); } +#if 0 unsigned n_fourop[2] = {0, 0}, n_total[2] = {0, 0}; for(unsigned a = 0; a < 256; ++a) { @@ -1778,6 +1786,7 @@ int main(int argc, char **argv) UI.PrintLn("This bank has %u/%u four-op melodic instruments", n_fourop[0], n_total[0]); UI.PrintLn(" and %u/%u percussive ones.", n_fourop[1], n_total[1]); } +#endif if(argc >= 4) { @@ -1790,6 +1799,7 @@ int main(int argc, char **argv) } adl_setNumCards(myDevice, (int)NumCards); } + if(argc >= 5) { NumFourOps = (unsigned)std::atoi(argv[4]); @@ -1800,14 +1810,21 @@ int main(int argc, char **argv) UI.ShowCursor(); return 0; } - adl_setNumFourOpsChn(myDevice, (int)NumFourOps); + if(adl_setNumFourOpsChn(myDevice, (int)NumFourOps) < 0) + { + UI.ShowCursor(); + std::fprintf(stderr, "%s\n", adl_errorInfo(myDevice)); + return 0; + } } + /* else NumFourOps = DoingInstrumentTesting ? 2 : (n_fourop[0] >= n_total[0] * 7 / 8) ? NumCards * 6 : (n_fourop[0] < n_total[0] * 1 / 8) ? 0 : (NumCards == 1 ? 1 : NumCards * 4); + */ if(WritingToTTY) { UI.PrintLn("Simulating %u OPL3 cards for a total of %u operators.", NumCards, NumCards * 36); @@ -1825,19 +1842,11 @@ int main(int argc, char **argv) UI.Color(7); if(adl_openFile(myDevice, argv[1]) != 0) { + std::fprintf(stderr, "%s\n", adl_errorInfo(myDevice)); UI.ShowCursor(); return 2; } - if(n_fourop[0] >= n_total[0] * 15 / 16 && NumFourOps == 0) - { - std::fprintf(stderr, - "ERROR: You have selected a bank that consists almost exclusively of four-op patches.\n" - " The results (silence + much cpu load) would be probably\n" - " not what you want, therefore ignoring the request.\n"); - return 0; - } - #ifdef __DJGPP__ unsigned TimerPeriod = 0x1234DDul / NewTimerFreq; @@ -1850,8 +1859,7 @@ int main(int argc, char **argv) #else - const double mindelay = 1 / (double)PCM_RATE; - const double maxdelay = MaxSamplesAtTime / (double)PCM_RATE; + //const double maxdelay = MaxSamplesAtTime / (double)PCM_RATE; #ifdef __WIN32 WindowsAudio::Open(PCM_RATE, 2, 16); @@ -1861,20 +1869,19 @@ int main(int argc, char **argv) #endif /* djgpp */ - // !!!ADL PRIVATE!!! - AdlInstrumentTester InstrumentTester(((MIDIplay *)myDevice->adl_midiPlayer)->opl); + AdlInstrumentTester InstrumentTester(myDevice); //static std::vector<int> sample_buf; - double delay = 0.0; + //double delay = 0.0; //sample_buf.resize(1024); short buff[1024]; UI.TetrisLaunched = true; while(!QuitFlag) { - #ifndef __DJGPP__ - const double eat_delay = delay < maxdelay ? delay : maxdelay; - delay -= eat_delay; +#ifndef __DJGPP__ + //const double eat_delay = delay < maxdelay ? delay : maxdelay; + //delay -= eat_delay; size_t got = 0; if(!DoingInstrumentTesting) @@ -1950,7 +1957,7 @@ int main(int argc, char **argv) #endif //fprintf(stderr, "Exit: %u\n", (unsigned)AudioBuffer.size()); //} - #else /* DJGPP */ +#else /* DJGPP */ UI.IllustrateVolumes(0, 0); const double mindelay = 1.0 / NewTimerFreq; @@ -1962,11 +1969,18 @@ int main(int argc, char **argv) const unsigned long CurTimer = BIOStimer; const double eat_delay = (CurTimer - PrevTimer) / (double)NewTimerFreq; PrevTimer = CurTimer; - #endif +#endif //double nextdelay = if(DoingInstrumentTesting) - InstrumentTester.Tick(eat_delay, mindelay); + { + if(!InstrumentTester.HandleInputChar(Input.PeekInput())) + QuitFlag = true; + #ifdef __DJGPP__ + else + delay = adl_tickEvents(myDevice, eat_delay, mindelay); + #endif + } //: player.Tick(eat_delay, mindelay); UI.GotoXY(0, 0); |