aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--libADLMIDI-test.pro3
-rw-r--r--src/adlmidi.cpp277
-rw-r--r--src/adlmidi.h4
-rw-r--r--src/adlmidi_load.cpp23
-rw-r--r--src/adlmidi_midiplay.cpp89
-rw-r--r--src/adlmidi_opl3.cpp24
-rw-r--r--src/adlmidi_private.hpp7
-rw-r--r--src/midiplay/adlmidiplay.cpp83
9 files changed, 215 insertions, 298 deletions
diff --git a/README.md b/README.md
index c49386f..01ab32e 100644
--- a/README.md
+++ b/README.md
@@ -88,6 +88,9 @@ To build that example you will need to have installed SDL2 library.
## 1.3.0 2017-10-17 <WIP>
* "gen_adldata" tool now supports WOPL banks format which supports a full set of libADLMIDI features
* Added support for custom banks are loadable in runtime without rebuilding of "adldata.cpp" banks database
+ * 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
* ...
## 1.2.1 2017-07-30
diff --git a/libADLMIDI-test.pro b/libADLMIDI-test.pro
index d83b80f..880d6b7 100644
--- a/libADLMIDI-test.pro
+++ b/libADLMIDI-test.pro
@@ -11,6 +11,8 @@ INCLUDEPATH += $$PWD/src
#LIBS += -Wl,-Bstatic -lSDL2 -Wl,-Bdynamic -lpthread -ldl
LIBS += -lSDL2 -lpthread -ldl
+#DEFINES += DISABLE_EMBEDDED_BANKS
+
HEADERS += \
src/adlbank.h \
src/adldata.hh \
@@ -23,6 +25,7 @@ HEADERS += \
SOURCES += \
src/adldata.cpp \
+ \
src/adlmidi.cpp \
src/adlmidi_load.cpp \
src/adlmidi_midiplay.cpp \
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
diff --git a/src/adlmidi.h b/src/adlmidi.h
index 752e307..5aa913b 100644
--- a/src/adlmidi.h
+++ b/src/adlmidi.h
@@ -48,7 +48,6 @@ struct ADL_MIDIPlayer
unsigned int AdlPercussionMode;
unsigned int LogarithmicVolumes;
int VolumeModel;
- unsigned int QuitFlag;
unsigned int SkipForward;
unsigned int QuitWithoutLooping;
unsigned int ScaleModulators;
@@ -128,6 +127,9 @@ extern int adl_openData(struct ADL_MIDIPlayer *device, void *mem, long size);
/*Resets MIDI player*/
extern void adl_reset(struct ADL_MIDIPlayer *device);
+/*Reset MIDI track position to begin */
+extern void adl_positionRewind(struct ADL_MIDIPlayer *device);
+
/*Close and delete ADLMIDI device*/
extern void adl_close(struct ADL_MIDIPlayer *device);
diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp
index 5258dc9..a1242d7 100644
--- a/src/adlmidi_load.cpp
+++ b/src/adlmidi_load.cpp
@@ -200,9 +200,8 @@ static bool readInstrument(MIDIplay::fileReader &file, WOPL_Inst &ins, bool isPe
bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
{
-#define qqq(x) (void)x
size_t fsize;
- qqq(fsize);
+ ADL_UNUSED(fsize);
if(!fr.isValid())
{
ADLMIDI_ErrorString = "Custom bank: Invalid data stream!";
@@ -296,6 +295,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
}
}
+ opl.AdlBank = opl._parent->AdlBank;
opl.dynamic_metainstruments.clear();
opl.dynamic_instruments.clear();
@@ -351,10 +351,7 @@ bool MIDIplay::LoadMIDI(const std::string &filename)
file.openFile(filename.c_str());
if(!LoadMIDI(file))
- {
- std::perror(filename.c_str());
return false;
- }
return true;
}
@@ -368,16 +365,23 @@ bool MIDIplay::LoadMIDI(void *data, unsigned long size)
bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
{
-#define qqq(x) (void)x
size_t fsize;
- qqq(fsize);
+ ADL_UNUSED(fsize);
//! Temp buffer for conversion
AdlMIDI_CPtr<uint8_t> cvt_buf;
- //std::FILE* fr = std::fopen(filename.c_str(), "rb");
+ #ifdef DISABLE_EMBEDDED_BANKS
+ if((opl.AdlBank != ~0u) || (opl.dynamic_metainstruments.size() < 256))
+ {
+ ADLMIDI_ErrorString = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!";
+ return false;
+ }
+ #endif
+
if(!fr.isValid())
{
- ADLMIDI_ErrorString = "Invalid data stream!";
+ ADLMIDI_ErrorString = "Invalid data stream!\n";
+ ADLMIDI_ErrorString += std::strerror(errno);
return false;
}
@@ -429,6 +433,7 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
opl.Reset();
trackStart = true;
+ atEnd = false;
loopStart = true;
loopStart_passed = false;
invalidLoop = false;
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 24dd60f..3b9d396 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -133,6 +133,7 @@ MIDIplay::MIDIplay():
cmf_percussion_mode(false),
config(NULL),
trackStart(false),
+ atEnd(false),
loopStart(false),
loopEnd(false),
loopStart_passed(false),
@@ -163,20 +164,18 @@ double MIDIplay::Tick(double s, double granularity)
if(CurrentPosition.began)
CurrentPosition.wait -= s;
- int AntiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing
-
- while((CurrentPosition.wait <= granularity * 0.5) && (AntiFreezeCounter > 0))
+ int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing
+ while((CurrentPosition.wait <= granularity * 0.5) && (antiFreezeCounter > 0))
{
//std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait);
- ProcessEvents();
-
+ if(!ProcessEvents())
+ break;
if(CurrentPosition.wait <= 0.0)
- AntiFreezeCounter--;
+ antiFreezeCounter--;
}
- if(AntiFreezeCounter <= 0)
+ if(antiFreezeCounter <= 0)
CurrentPosition.wait += 1.0;/* Add extra 1 second when over 10000 events
-
with zero delay are been detected */
for(uint16_t c = 0; c < opl.NumChannels; ++c)
@@ -184,9 +183,21 @@ double MIDIplay::Tick(double s, double granularity)
UpdateVibrato(s);
UpdateArpeggio(s);
+
return CurrentPosition.wait;
}
+void MIDIplay::rewind()
+{
+ CurrentPosition = trackBeginPosition;
+ trackStart = true;
+ atEnd = false;
+ loopStart = true;
+ loopStart_passed = false;
+ invalidLoop = false;
+ loopStart_hit = false;
+}
+
void MIDIplay::realTime_ResetState()
{
for(size_t ch = 0; ch < Ch.size(); ch++)
@@ -358,7 +369,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
}
}
- long s = CalculateAdlChannelGoodness(a, i[ccount], channel );
+ long s = CalculateAdlChannelGoodness(a, i[ccount], channel);
if(s > bs)
{
@@ -809,8 +820,13 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
}
-void MIDIplay::ProcessEvents()
+bool MIDIplay::ProcessEvents()
{
+ if(TrackData.size() == 0)
+ atEnd = true;//No MIDI track data to play
+ if(atEnd)
+ return false;//No more events in the queue
+
loopEnd = false;
const size_t TrackCount = TrackData.size();
const Position RowBeginPosition(CurrentPosition);
@@ -877,6 +893,7 @@ void MIDIplay::ProcessEvents()
{
trackBeginPosition = RowBeginPosition;
trackStart = false;
+ atEnd = false;
}
LoopBeginPosition = RowBeginPosition;
loopStart = false;
@@ -885,16 +902,19 @@ void MIDIplay::ProcessEvents()
if(shortest_no || loopEnd)
{
- // Loop if song end reached
+ //Loop if song end or loop end point has reached
loopEnd = false;
- CurrentPosition = LoopBeginPosition;
shortest = 0;
- if(opl._parent->QuitWithoutLooping == 1)
+ if(opl._parent->QuitWithoutLooping != 0)
{
- opl._parent->QuitFlag = 1;
- //^ HACK: QUIT WITHOUT LOOPING
+ atEnd = true; //Don't handle events anymore
+ CurrentPosition.wait += 1.0;//One second delay until stop playing
+ return true;//We have caugh end here!
}
+ CurrentPosition = LoopBeginPosition;
}
+
+ return true;//Has events in queue
}
void MIDIplay::HandleEvent(size_t tk)
@@ -932,25 +952,29 @@ void MIDIplay::HandleEvent(size_t tk)
if(evtype == 6)
{
- /* Move this away from events handler */
- for(size_t i = 0; i < data.size(); i++)
+ //Turn on/off Loop handling
+ if(opl._parent->QuitWithoutLooping == 0)
{
- if(data[i] <= 'Z' && data[i] >= 'A')
- data[i] = data[i] - ('Z' - 'z');
- }
+ /* Move this away from events handler */
+ 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 == "loopstart") && (!invalidLoop))
+ {
+ loopStart = true;
+ loopStart_passed = true;
+ }
- if((data == "loopend") && (!invalidLoop))
- {
- if((loopStart_passed) && (!loopStart))
- loopEnd = true;
- else
- invalidLoop = true;
+ if((data == "loopend") && (!invalidLoop))
+ {
+ if((loopStart_passed) && (!loopStart))
+ loopEnd = true;
+ else
+ invalidLoop = true;
+ }
}
}
@@ -1034,12 +1058,13 @@ void MIDIplay::HandleEvent(size_t tk)
uint8_t ctrlno = TrackData[tk][CurrentPosition.track[tk].ptr++];
uint8_t value = TrackData[tk][CurrentPosition.track[tk].ptr++];
- if((ctrlno == 111) && !invalidLoop)
+ if((opl._parent->QuitWithoutLooping == 0) && (ctrlno == 111) && !invalidLoop)
{
loopStart = true;
loopStart_passed = true;
break;
}
+
realTime_Controller(MidCh, ctrlno, value);
break;
}
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index 7ae2486..d03b942 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -23,6 +23,30 @@
#include "adlmidi_private.hpp"
+#ifdef DISABLE_EMBEDDED_BANKS
+/*
+ Dummy data which replaces adldata.cpp banks database
+*/
+
+const struct adldata adl[]
+{
+ {0, 0, 0, 0, 0, 0}
+};
+
+const struct adlinsdata adlins[] =
+{
+ {0, 0, 0, 0, 0, 0, 0.0}
+};
+
+int maxAdlBanks()
+{
+ return 0;
+}
+
+const unsigned short banks[][256] = {{0}};
+const char* const banknames[] = {"<Embedded banks are disabled>"};
+#endif
+
static const unsigned short Operators[23 * 2] =
{
// Channels 0-2
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 7bb5774..e039f85 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -75,6 +75,8 @@
#include "adldata.hh"
#include "adlmidi.h"
+#define ADL_UNUSED(x) (void)x
+
extern std::string ADLMIDI_ErrorString;
/*
@@ -299,6 +301,7 @@ public:
std::string musTitle;
fraction<uint64_t> InvDeltaTicks, Tempo;
bool trackStart,
+ atEnd,
loopStart,
loopEnd,
loopStart_passed /*Tells that "loopStart" already passed*/,
@@ -470,6 +473,8 @@ public:
*/
double Tick(double s, double granularity);
+ void rewind();
+
/* RealTime event triggers */
void realTime_ResetState();
@@ -505,7 +510,7 @@ private:
MIDIchannel::activenoteiterator i,
unsigned props_mask,
int32_t select_adlchn = -1);
- void ProcessEvents();
+ bool ProcessEvents();
void HandleEvent(size_t tk);
// Determine how good a candidate this adlchannel
diff --git a/src/midiplay/adlmidiplay.cpp b/src/midiplay/adlmidiplay.cpp
index 0cefb7c..cbea468 100644
--- a/src/midiplay/adlmidiplay.cpp
+++ b/src/midiplay/adlmidiplay.cpp
@@ -58,6 +58,12 @@ static bool is_number(const std::string &s)
return !s.empty() && it == s.end();
}
+static void printError(const char *err)
+{
+ std::fprintf(stderr, "\nERROR: %s\n\n", err);
+ std::fflush(stderr);
+}
+
#undef main
int main(int argc, char **argv)
{
@@ -83,23 +89,29 @@ int main(int argc, char **argv)
int banksCount = adl_getBanksCount();
const char* const* banknames = adl_getBankNames();
- std::printf(" Available embedded banks by number:\n\n");
+ if(banksCount > 0)
+ {
+ std::printf(" Available embedded banks by number:\n\n");
- for(int a = 0; a < banksCount; ++a)
- std::printf("%10s%2u = %s\n", a ? "" : "Banks:", a, banknames[a]);
+ for(int a = 0; a < banksCount; ++a)
+ std::printf("%10s%2u = %s\n", a ? "" : "Banks:", a, banknames[a]);
+
+ std::printf(
+ "\n"
+ " 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"
+ );
+ } else {
+ std::printf(" This build of libADLMIDI has no embedded banks!\n\n");
+ }
- std::printf(
- "\n"
- " 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;
}
@@ -119,13 +131,13 @@ int main(int argc, char **argv)
spec.freq = 44100;
spec.format = AUDIO_S16SYS;
spec.channels = 2;
- spec.samples = spec.freq * AudioBufferLength;
+ spec.samples = Uint16((double)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());
+ std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", SDL_GetError());
//return 1;
}
if(spec.samples != obtained.samples)
@@ -137,7 +149,7 @@ int main(int argc, char **argv)
myDevice = adl_init(44100);
if(myDevice == NULL)
{
- std::fprintf(stderr, "Failed to init MIDI device!\n");
+ printError("Failed to init MIDI device!\n");
return 1;
}
@@ -170,8 +182,7 @@ int main(int argc, char **argv)
int bankno = std::atoi(argv[2]);
if(adl_setBank(myDevice, bankno) != 0)
{
- std::fprintf(stderr, "%s\n", adl_errorString());
- std::fflush(stderr);
+ printError(adl_errorString());
return 0;
}
}
@@ -183,8 +194,7 @@ int main(int argc, char **argv)
{
std::fprintf(stdout, "FAILED!\n");
std::fflush(stdout);
- std::fprintf(stderr, "%s\n", adl_errorString());
- std::fflush(stderr);
+ printError(adl_errorString());
return 0;
}
std::fprintf(stdout, "OK!\n");
@@ -196,16 +206,26 @@ int main(int argc, char **argv)
{
if(adl_setNumCards(myDevice, std::atoi(argv[3])) != 0)
{
- std::fprintf(stderr, "%s\n", adl_errorString());
+ printError(adl_errorString());
return 0;
}
std::fprintf(stdout, "Number of cards %s\n", argv[3]);
}
+ else
+ {
+ // 4 chips by default
+ if(adl_setNumCards(myDevice, 4) != 0)
+ {
+ printError(adl_errorString());
+ return 0;
+ }
+ }
+
if(argc >= 5)
{
if(adl_setNumFourOpsChn(myDevice, std::atoi(argv[4])) != 0)
{
- std::fprintf(stderr, "%s\n", adl_errorString());
+ printError(adl_errorString());
return 0;
}
std::fprintf(stdout, "Number of four-ops %s\n", argv[4]);
@@ -213,7 +233,7 @@ int main(int argc, char **argv)
if(adl_openFile(myDevice, argv[1]) != 0)
{
- std::fprintf(stderr, "%s\n", adl_errorString());
+ printError(adl_errorString());
return 2;
}
@@ -222,18 +242,19 @@ int main(int argc, char **argv)
while(1)
{
short buff[4096];
- unsigned long gotten = adl_play(myDevice, 4096, buff);
- if(gotten <= 0) break;
+ size_t got = (size_t)adl_play(myDevice, 4096, buff);
+ if(got <= 0)
+ break;
AudioBuffer_lock.Lock();
size_t pos = AudioBuffer.size();
- AudioBuffer.resize(pos + gotten);
- for(unsigned long p = 0; p < gotten; ++p)
+ AudioBuffer.resize(pos + got);
+ for(size_t p = 0; p < got; ++p)
AudioBuffer[pos + p] = buff[p];
AudioBuffer_lock.Unlock();
- const SDL_AudioSpec &spec_ = obtained;
- while(AudioBuffer.size() > spec_.samples + (spec_.freq * 2) * OurHeadRoomLength)
+ const SDL_AudioSpec &spec = obtained;
+ while(AudioBuffer.size() > spec.samples + (spec.freq * 2) * OurHeadRoomLength)
{
SDL_Delay(1);
}