aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/adlmidi.cpp91
-rw-r--r--src/adlmidi_load.cpp42
-rw-r--r--src/adlmidi_midiplay.cpp204
-rw-r--r--src/adlmidi_mus2mid.h9
-rw-r--r--src/adlmidi_opl3.cpp32
-rw-r--r--src/adlmidi_private.cpp4
-rw-r--r--src/adlmidi_private.hpp92
-rw-r--r--src/adlmidi_xmi2mid.h9
-rw-r--r--src/fraction.hpp (renamed from src/fraction.h)0
9 files changed, 406 insertions, 77 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp
index 59d7a7e..dc9c980 100644
--- a/src/adlmidi.cpp
+++ b/src/adlmidi.cpp
@@ -23,7 +23,11 @@
#include "adlmidi_private.hpp"
+#ifdef ADLMIDI_HW_OPL
+static const unsigned MaxCards = 1;
+#else
static const unsigned MaxCards = 100;
+#endif
/*---------------------------EXPORTS---------------------------*/
@@ -31,7 +35,20 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate)
{
ADL_MIDIPlayer *midi_device;
midi_device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer));
+ if(!midi_device)
+ {
+ ADLMIDI_ErrorString = "Can't initialize ADLMIDI: out of memory!";
+ return NULL;
+ }
+
MIDIplay *player = new MIDIplay;
+ if(!player)
+ {
+ free(midi_device);
+ ADLMIDI_ErrorString = "Can't initialize ADLMIDI: out of memory!";
+ return NULL;
+ }
+
midi_device->adl_midiPlayer = player;
player->m_setup.PCM_RATE = static_cast<unsigned long>(sample_rate);
player->m_setup.mindelay = 1.0 / (double)player->m_setup.PCM_RATE;
@@ -52,7 +69,7 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards)
{
std::stringstream s;
s << "number of cards may only be 1.." << MaxCards << ".\n";
- ADLMIDI_ErrorString = s.str();
+ play->setErrorString(s.str());
return -1;
}
@@ -83,7 +100,7 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank)
{
std::stringstream s;
s << "bank number may only be 0.." << (NumBanks - 1) << ".\n";
- ADLMIDI_ErrorString = s.str();
+ play->setErrorString(s.str());
return -1;
}
@@ -113,7 +130,7 @@ ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4)
{
std::stringstream s;
s << "number of four-op channels may only be 0.." << (6 * (play->m_setup.NumCards)) << " when " << play->m_setup.NumCards << " OPL3 cards are used.\n";
- ADLMIDI_ErrorString = s.str();
+ play->setErrorString(s.str());
return -1;
}
@@ -178,8 +195,6 @@ ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int v
ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePath)
{
- ADLMIDI_ErrorString.clear();
-
if(device && device->adl_midiPlayer)
{
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
@@ -187,8 +202,9 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePat
play->m_setup.backup_samples_size = 0;
if(!play->LoadBank(filePath))
{
- if(ADLMIDI_ErrorString.empty())
- ADLMIDI_ErrorString = "ADL MIDI: Can't load file";
+ std::string err = play->getErrorString();
+ if(err.empty())
+ play->setErrorString("ADL MIDI: Can't load file");
return -1;
}
else return 0;
@@ -200,8 +216,6 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePat
ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, long size)
{
- ADLMIDI_ErrorString.clear();
-
if(device && device->adl_midiPlayer)
{
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
@@ -209,8 +223,9 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, lo
play->m_setup.backup_samples_size = 0;
if(!play->LoadBank(mem, static_cast<size_t>(size)))
{
- if(ADLMIDI_ErrorString.empty())
- ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory";
+ std::string err = play->getErrorString();
+ if(err.empty())
+ play->setErrorString("ADL MIDI: Can't load data from memory");
return -1;
}
else return 0;
@@ -222,8 +237,6 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, lo
ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
{
- ADLMIDI_ErrorString.clear();
-
if(device && device->adl_midiPlayer)
{
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
@@ -231,8 +244,9 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
play->m_setup.backup_samples_size = 0;
if(!play->LoadMIDI(filePath))
{
- if(ADLMIDI_ErrorString.empty())
- ADLMIDI_ErrorString = "ADL MIDI: Can't load file";
+ std::string err = play->getErrorString();
+ if(err.empty())
+ play->setErrorString("ADL MIDI: Can't load file");
return -1;
}
else return 0;
@@ -244,8 +258,6 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, void *mem, long size)
{
- ADLMIDI_ErrorString.clear();
-
if(device && device->adl_midiPlayer)
{
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
@@ -253,13 +265,13 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, void *mem, long size)
play->m_setup.backup_samples_size = 0;
if(!play->LoadMIDI(mem, static_cast<size_t>(size)))
{
- if(ADLMIDI_ErrorString.empty())
- ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory";
+ std::string err = play->getErrorString();
+ if(err.empty())
+ play->setErrorString("ADL MIDI: Can't load data from memory");
return -1;
}
else return 0;
}
-
ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized";
return -1;
}
@@ -274,16 +286,35 @@ ADLMIDI_EXPORT const char *adl_emulatorName()
#endif
}
+ADLMIDI_EXPORT const char *adl_linkedLibraryVersion()
+{
+ return ADLMIDI_VERSION;
+}
+
+
ADLMIDI_EXPORT const char *adl_errorString()
{
return ADLMIDI_ErrorString.c_str();
}
+ADLMIDI_EXPORT const char *adl_errorInfo(ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return adl_errorString();
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(!play)
+ return adl_errorString();
+ return play->getErrorString().c_str();
+}
+
ADLMIDI_EXPORT const char *adl_getMusicTitle(ADL_MIDIPlayer *device)
{
if(!device)
return "";
- return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musTitle.c_str();
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(!play)
+ return "";
+ return play->musTitle.c_str();
}
ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device)
@@ -477,6 +508,9 @@ inline static void SendStereoAudio(MIDIplay::Setup &device,
ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
{
+ #ifdef ADLMIDI_HW_OPL
+ return 0;
+ #else
sampleCount -= sampleCount % 2; //Avoid even sample requests
if(sampleCount < 0)
return 0;
@@ -573,11 +607,15 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
}
return static_cast<int>(gotten_len);
+ #endif
}
ADLMIDI_EXPORT int adl_generate(ADL_MIDIPlayer *device, int sampleCount, short *out)
{
+ #ifdef ADLMIDI_HW_OPL
+ return 0;
+ #else
sampleCount -= sampleCount % 2; //Avoid even sample requests
if(sampleCount < 0)
return 0;
@@ -617,4 +655,15 @@ ADLMIDI_EXPORT int adl_generate(ADL_MIDIPlayer *device, int sampleCount, short *
}
return sampleCount;
+ #endif
+}
+
+ADLMIDI_EXPORT double adl_tickEvents(ADL_MIDIPlayer *device, double seconds, double granuality)
+{
+ if(!device)
+ return -1.0;
+ MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(!player)
+ return -1.0;
+ return player->Tick(seconds, granuality);
}
diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp
index 16881d4..76765dc 100644
--- a/src/adlmidi_load.cpp
+++ b/src/adlmidi_load.cpp
@@ -176,7 +176,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
ADL_UNUSED(fsize);
if(!fr.isValid())
{
- ADLMIDI_ErrorString = "Custom bank: Invalid data stream!";
+ errorStringOut = "Custom bank: Invalid data stream!";
return false;
}
@@ -190,27 +190,27 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
if(fr.read(magic, 1, 11) != 11)
{
- ADLMIDI_ErrorString = "Custom bank: Can't read magic number!";
+ errorStringOut = "Custom bank: Can't read magic number!";
return false;
}
if(strncmp(magic, wopl3_magic, 11) != 0)
{
- ADLMIDI_ErrorString = "Custom bank: Invalid magic number!";
+ errorStringOut = "Custom bank: Invalid magic number!";
return false;
}
uint8_t version_raw[2];
if(fr.read(version_raw, 1, 2) != 2)
{
- ADLMIDI_ErrorString = "Custom bank: Can't read version!";
+ errorStringOut = "Custom bank: Can't read version!";
return false;
}
version = toUint16LE(version_raw);
if(version > wopl_latest_version)
{
- ADLMIDI_ErrorString = "Custom bank: Unsupported WOPL version!";
+ errorStringOut = "Custom bank: Unsupported WOPL version!";
return false;
}
@@ -218,7 +218,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
memset(head, 0, 6);
if(fr.read(head, 1, 6) != 6)
{
- ADLMIDI_ErrorString = "Custom bank: Can't read header!";
+ errorStringOut = "Custom bank: Can't read header!";
return false;
}
@@ -227,7 +227,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
if((count_melodic_banks < 1) || (count_percusive_banks < 1))
{
- ADLMIDI_ErrorString = "Custom bank: Too few banks in this file!";
+ errorStringOut = "Custom bank: Too few banks in this file!";
return false;
}
@@ -248,7 +248,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
uint8_t bank_meta[34];
if(fr.read(bank_meta, 1, 34) != 34)
{
- ADLMIDI_ErrorString = "Custom bank: Fail to read melodic bank meta-data!";
+ errorStringOut = "Custom bank: Fail to read melodic bank meta-data!";
return false;
}
//strncpy(bankMeta.name, char_p(bank_meta), 32);
@@ -261,7 +261,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
uint8_t bank_meta[34];
if(fr.read(bank_meta, 1, 34) != 34)
{
- ADLMIDI_ErrorString = "Custom bank: Fail to read melodic bank meta-data!";
+ errorStringOut = "Custom bank: Fail to read melodic bank meta-data!";
return false;
}
//strncpy(bankMeta.name, char_p(bank_meta), 32);
@@ -286,7 +286,7 @@ tryAgain:
{
opl.dynamic_metainstruments.clear();
opl.dynamic_instruments.clear();
- ADLMIDI_ErrorString = "Custom bank: Fail to read instrument!";
+ errorStringOut = "Custom bank: Fail to read instrument!";
return false;
}
@@ -356,9 +356,9 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
if(!fr.isValid())
{
- ADLMIDI_ErrorString = "Invalid data stream!\n";
+ errorStringOut = "Invalid data stream!\n";
#ifndef _WIN32
- ADLMIDI_ErrorString += std::strerror(errno);
+ errorStringOut += std::strerror(errno);
#endif
return false;
}
@@ -423,7 +423,7 @@ riffskip:
uint8_t *mus = (uint8_t *)malloc(mus_len);
if(!mus)
{
- ADLMIDI_ErrorString = "Out of memory!";
+ errorStringOut = "Out of memory!";
return false;
}
fr.read(mus, 1, mus_len);
@@ -437,7 +437,7 @@ riffskip:
if(mus) free(mus);
if(m2mret < 0)
{
- ADLMIDI_ErrorString = "Invalid MUS/DMX data format!";
+ errorStringOut = "Invalid MUS/DMX data format!";
return false;
}
cvt_buf.reset(mid);
@@ -451,7 +451,7 @@ riffskip:
if(std::memcmp(HeaderBuf + 8, "XDIR", 4) != 0)
{
fr.close();
- ADLMIDI_ErrorString = fr._fileName + ": Invalid format\n";
+ errorStringOut = fr._fileName + ": Invalid format\n";
return false;
}
@@ -461,7 +461,7 @@ riffskip:
uint8_t *mus = (uint8_t *)malloc(mus_len);
if(!mus)
{
- ADLMIDI_ErrorString = "Out of memory!";
+ errorStringOut = "Out of memory!";
return false;
}
fr.read(mus, 1, mus_len);
@@ -475,7 +475,7 @@ riffskip:
if(mus) free(mus);
if(m2mret < 0)
{
- ADLMIDI_ErrorString = "Invalid XMI data format!";
+ errorStringOut = "Invalid XMI data format!";
return false;
}
cvt_buf.reset(mid);
@@ -613,7 +613,7 @@ riffskip:
if(std::memcmp(HeaderBuf, "MThd\0\0\0\6", 8) != 0)
{
fr.close();
- ADLMIDI_ErrorString = fr._fileName + ": Invalid format, Header signature is unknown!\n";
+ errorStringOut = fr._fileName + ": Invalid format, Header signature is unknown!\n";
return false;
}
@@ -710,7 +710,7 @@ riffskip:
if(std::memcmp(HeaderBuf, "MTrk", 4) != 0)
{
fr.close();
- ADLMIDI_ErrorString = fr._fileName + ": Invalid format, MTrk signature is not found!\n";
+ errorStringOut = fr._fileName + ": Invalid format, MTrk signature is not found!\n";
return false;
}
TrackLength = (size_t)ReadBEint(HeaderBuf + 4, 4);
@@ -746,14 +746,14 @@ riffskip:
if(totalGotten == 0)
{
- ADLMIDI_ErrorString = fr._fileName + ": Empty track data";
+ errorStringOut = fr._fileName + ": Empty track data";
return false;
}
//Build new MIDI events table (ALPHA!!!)
if(!buildTrackData())
{
- ADLMIDI_ErrorString = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString;
+ errorStringOut = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString;
return false;
}
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index fa95e32..7d1ba75 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -529,9 +529,9 @@ bool MIDIplay::buildTrackData()
#if 1 //Use this to record WAVEs for comparison before/after implementing of this
if(opl.m_musicMode == OPL3::MODE_MIDI)//Percussion fix is needed for MIDI only, not for IMF/RSXX or CMF
{
-//! Minimal real time in seconds
+ //! Minimal real time in seconds
#define DRUM_NOTE_MIN_TIME 0.03
-//! Minimal ticks count
+ //! Minimal ticks count
#define DRUM_NOTE_MIN_TICKS 15
struct NoteState
{
@@ -1778,6 +1778,16 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &stat
return evt;
}
+const std::string &MIDIplay::getErrorString()
+{
+ return errorStringOut;
+}
+
+void MIDIplay::setErrorString(const std::string &err)
+{
+ errorStringOut = err;
+}
+
void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
{
@@ -2323,3 +2333,193 @@ retry_arpeggio:
}
}
}
+
+
+#ifndef ADLMIDI_DISABLE_CPP_EXTRAS
+
+ADLMIDI_EXPORT AdlInstrumentTester::AdlInstrumentTester(ADL_MIDIPlayer *device)
+{
+ cur_gm = 0;
+ ins_idx = 0;
+ play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ if(!play)
+ return;
+ opl = &play->opl;
+}
+
+ADLMIDI_EXPORT AdlInstrumentTester::~AdlInstrumentTester()
+{}
+
+ADLMIDI_EXPORT void AdlInstrumentTester::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();
+}
+
+
+
+ADLMIDI_EXPORT void AdlInstrumentTester::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);
+ }
+}
+
+ADLMIDI_EXPORT void AdlInstrumentTester::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
+ if(play->hooks.onDebugMessage)
+ {
+ play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData,
+ "noteon at %d(%d) for %g Hz\n", adlchannel[0], i[0], hertz);
+ }
+ }
+ else
+ {
+ if(play->hooks.onDebugMessage)
+ {
+ play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData,
+ "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);
+ }
+}
+
+ADLMIDI_EXPORT void AdlInstrumentTester::NextGM(int offset)
+{
+ cur_gm = (cur_gm + 256 + (uint32_t)offset) & 0xFF;
+ FindAdlList();
+}
+
+ADLMIDI_EXPORT void AdlInstrumentTester::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();
+
+ #if 0
+ 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);
+ #endif
+
+ 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");
+ }
+}
+
+ADLMIDI_EXPORT bool AdlInstrumentTester::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;
+ default:
+ const char *p = strchr(notes, ch);
+ if(p && *p)
+ DoNote((p - notes) - 12);
+ }
+ return true;
+}
+
+#endif//ADLMIDI_DISABLE_CPP_EXTRAS
diff --git a/src/adlmidi_mus2mid.h b/src/adlmidi_mus2mid.h
index c56c359..cc41b87 100644
--- a/src/adlmidi_mus2mid.h
+++ b/src/adlmidi_mus2mid.h
@@ -24,6 +24,15 @@
#include <stdint.h>
+#ifdef __DJGPP__
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed long int32_t;
+typedef unsigned long uint32_t;
+#endif
+
#ifdef __cplusplus
extern "C"
{
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index ed005b1..ce26ba6 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -23,6 +23,10 @@
#include "adlmidi_private.hpp"
+#ifdef ADLMIDI_HW_OPL
+static const unsigned OPLBase = 0x388;
+#endif
+
#ifdef DISABLE_EMBEDDED_BANKS
/*
Dummy data which replaces adldata.cpp banks database
@@ -151,20 +155,38 @@ OPL3::OPL3() :
void OPL3::Poke(size_t card, uint32_t index, uint32_t value)
{
+ #ifdef ADLMIDI_HW_OPL
+ unsigned o = index >> 8;
+ unsigned port = OPLBase + o * 2;
+ outportb(port, index);
+ for(unsigned c = 0; c < 6; ++c) inportb(port);
+ outportb(port + 1, value);
+ for(unsigned c = 0; c < 35; ++c) inportb(port);
+ #else
#ifdef ADLMIDI_USE_DOSBOX_OPL
cards[card].WriteReg(index, static_cast<uint8_t>(value));
#else
OPL3_WriteReg(&cards[card], static_cast<Bit16u>(index), static_cast<Bit8u>(value));
#endif
+ #endif
}
void OPL3::PokeN(size_t card, uint16_t index, uint8_t value)
{
+ #ifdef ADLMIDI_HW_OPL
+ unsigned o = index >> 8;
+ unsigned port = OPLBase + o * 2;
+ outportb(port, index);
+ for(unsigned c = 0; c < 6; ++c) inportb(port);
+ outportb(port + 1, value);
+ for(unsigned c = 0; c < 35; ++c) inportb(port);
+ #else
#ifdef ADLMIDI_USE_DOSBOX_OPL
cards[card].WriteReg(static_cast<Bit32u>(index), value);
#else
OPL3_WriteReg(&cards[card], index, value);
#endif
+ #endif
}
@@ -427,11 +449,15 @@ void OPL3::Reset(unsigned long PCM_RATE)
_opl3_chip emptyChip;
std::memset(&emptyChip, 0, sizeof(_opl3_chip));
#endif
+ #ifndef ADLMIDI_HW_OPL
cards.clear();
+ #endif
ins.clear();
pit.clear();
regBD.clear();
+ #ifndef ADLMIDI_HW_OPL
cards.resize(NumCards, emptyChip);
+ #endif
NumChannels = NumCards * 23;
ins.resize(NumChannels, 189);
pit.resize(NumChannels, 0);
@@ -454,10 +480,12 @@ void OPL3::Reset(unsigned long PCM_RATE)
for(unsigned card = 0; card < NumCards; ++card)
{
- #ifdef ADLMIDI_USE_DOSBOX_OPL
+ #ifndef ADLMIDI_HW_OPL
+ # ifdef ADLMIDI_USE_DOSBOX_OPL
cards[card].Init(PCM_RATE);
- #else
+ # else
OPL3_Reset(&cards[card], static_cast<Bit32u>(PCM_RATE));
+ # endif
#endif
for(unsigned a = 0; a < 18; ++a) Poke(card, 0xB0 + Channels[a], 0x00);
diff --git a/src/adlmidi_private.cpp b/src/adlmidi_private.cpp
index 04bb481..f13aa8c 100644
--- a/src/adlmidi_private.cpp
+++ b/src/adlmidi_private.cpp
@@ -65,9 +65,9 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device)
if(n_fourop[0] >= n_total[0] * 15 / 16 && play->m_setup.NumFourOps == 0)
{
- ADLMIDI_ErrorString = "ERROR: You have selected a bank that consists almost exclusively of four-op patches.\n"
+ play->setErrorString("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";
+ " not what you want, therefore ignoring the request.\n");
return -1;
}
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 650291a..698dad5 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -24,29 +24,43 @@
#ifndef ADLMIDI_PRIVATE_HPP
#define ADLMIDI_PRIVATE_HPP
+#ifndef ADLMIDI_VERSION
+#define ADLMIDI_VERSION "1.3.0"
+#endif
+
// Setup compiler defines useful for exporting required public API symbols in gme.cpp
#ifndef ADLMIDI_EXPORT
- #if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL)
- #define ADLMIDI_EXPORT __declspec(dllexport)
- #elif defined (LIBADLMIDI_VISIBILITY)
- #define ADLMIDI_EXPORT __attribute__((visibility ("default")))
- #else
- #define ADLMIDI_EXPORT
- #endif
+# if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL)
+# define ADLMIDI_EXPORT __declspec(dllexport)
+# elif defined (LIBADLMIDI_VISIBILITY)
+# define ADLMIDI_EXPORT __attribute__((visibility ("default")))
+# else
+# define ADLMIDI_EXPORT
+# endif
#endif
#ifdef _WIN32
- #undef NO_OLDNAMES
-
- #ifdef _MSC_VER
- #ifdef _WIN64
- typedef __int64 ssize_t;
- #else
- typedef __int32 ssize_t;
- #endif
- #define NOMINMAX //Don't override std::min and std::max
- #endif
- #include <windows.h>
+# undef NO_OLDNAMES
+
+# ifdef _MSC_VER
+# ifdef _WIN64
+typedef __int64 ssize_t;
+# else
+typedef __int32 ssize_t;
+# endif
+# define NOMINMAX //Don't override std::min and std::max
+# endif
+# include <windows.h>
+#endif
+
+#ifdef __DJGPP__
+#define ADLMIDI_HW_OPL
+#include <conio.h>
+#include <pc.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <sys/farptr.h>
+#include <dos.h>
#endif
#include <vector>
@@ -72,15 +86,19 @@
#include <deque>
#include <algorithm>
-#include "fraction.h"
+#include "fraction.hpp"
+
#ifdef ADLMIDI_USE_DOSBOX_OPL
- #include "dbopl.h"
+#include "dbopl.h"
#else
- #include "nukedopl3.h"
+#include "nukedopl3.h"
#endif
#include "adldata.hh"
-#include "adlmidi.h"
+#include "adlmidi.h" //Main API
+#ifndef ADLMIDI_DISABLE_CPP_EXTRAS
+#include "adlmidi.hpp" //Extra C++ API
+#endif
#define ADL_UNUSED(x) (void)x
@@ -93,7 +111,7 @@ extern std::string ADLMIDI_ErrorString;
template<class PTR>
class AdlMIDI_CPtr
{
- PTR* m_p;
+ PTR *m_p;
public:
AdlMIDI_CPtr() : m_p(NULL) {}
~AdlMIDI_CPtr()
@@ -108,9 +126,18 @@ public:
m_p = p;
}
- PTR* get() { return m_p;}
- PTR& operator*() { return *m_p; }
- PTR* operator->() { return m_p; }
+ PTR *get()
+ {
+ return m_p;
+ }
+ PTR &operator*()
+ {
+ return *m_p;
+ }
+ PTR *operator->()
+ {
+ return m_p;
+ }
};
class MIDIplay;
@@ -120,11 +147,13 @@ struct OPL3
uint32_t NumChannels;
char ____padding[4];
ADL_MIDIPlayer *_parent;
+ #ifndef ADLMIDI_HW_OPL
#ifdef ADLMIDI_USE_DOSBOX_OPL
std::vector<DBOPL::Handler> cards;
#else
std::vector<_opl3_chip> cards;
#endif
+ #endif
private:
std::vector<size_t> ins; // index to adl[], cached, needed by Touch()
std::vector<uint8_t> pit; // value poked to B0, cached, needed by NoteOff)(
@@ -134,7 +163,7 @@ private:
std::vector<adlinsdata> dynamic_metainstruments; // Replaces adlins[] when CMF file
std::vector<adldata> dynamic_instruments; // Replaces adl[] when CMF file
const unsigned DynamicInstrumentTag /* = 0x8000u*/,
- DynamicMetaInstrumentTag /* = 0x4000000u*/;
+ DynamicMetaInstrumentTag /* = 0x4000000u*/;
public:
const adlinsdata &GetAdlMetaIns(unsigned n);
unsigned GetAdlMetaNumber(unsigned midiins);
@@ -540,9 +569,9 @@ public:
ST_ENDTRACK = 0x2F,//size == 0
ST_TEMPOCHANGE = 0x51,//size == 3
ST_SMPTEOFFSET = 0x54,//size == 5
- ST_TIMESIGNATURE= 0x55,//size == 4
+ ST_TIMESIGNATURE = 0x55, //size == 4
ST_KEYSIGNATURE = 0x59,//size == 2
- ST_SEQUENCERSPEC= 0x7F,//size == len
+ ST_SEQUENCERSPEC = 0x7F, //size == len
/* Non-standard, internal ADLMIDI usage only */
ST_LOOPSTART = 0xE1,//size == 0 <CUSTOM>
@@ -690,6 +719,8 @@ private:
double loopEndTime;
//! Local error string
std::string errorString;
+ //! Local error string
+ std::string errorStringOut;
//! Pre-processed track data storage
std::vector<MidiTrackQueue > trackDataNew;
@@ -714,6 +745,9 @@ private:
public:
+ const std::string &getErrorString();
+ void setErrorString(const std::string &err);
+
std::string musTitle;
std::string musCopyright;
std::vector<std::string> musTrackTitles;
diff --git a/src/adlmidi_xmi2mid.h b/src/adlmidi_xmi2mid.h
index 523e8d7..950d58c 100644
--- a/src/adlmidi_xmi2mid.h
+++ b/src/adlmidi_xmi2mid.h
@@ -27,6 +27,15 @@
#include <stdint.h>
+#ifdef __DJGPP__
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed long int32_t;
+typedef unsigned long uint32_t;
+#endif
+
#ifdef __cplusplus
extern "C"
{
diff --git a/src/fraction.h b/src/fraction.hpp
index 1ec10ab..1ec10ab 100644
--- a/src/fraction.h
+++ b/src/fraction.hpp