aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/adlmidi.cpp216
-rw-r--r--src/adlmidi.h8
2 files changed, 135 insertions, 89 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp
index 246f5f7..a994fa0 100644
--- a/src/adlmidi.cpp
+++ b/src/adlmidi.cpp
@@ -415,7 +415,9 @@ class MIDIplay
std::vector<TrackInfo> track;
Position(): began(false), wait(0.0), track() { }
- } CurrentPosition, LoopBeginPosition;
+ };
+ Position CurrentPosition, LoopBeginPosition, trackBeginPosition;
+
std::map<std::string, unsigned> devices;
std::map<unsigned/*track*/, unsigned/*channel begin index*/> current_device;
@@ -515,8 +517,12 @@ class MIDIplay
public:
std::string musTitle;
fraction<long> InvDeltaTicks, Tempo;
- bool loopStart, loopEnd, invalidLoop;
- long loopStart_ticks, loopEnd_ticks;
+ bool trackStart,
+ loopStart,
+ loopEnd,
+ loopStart_passed /*Tells that "loopStart" already passed*/,
+ invalidLoop /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/,
+ loopStart_hit /*loopStart entry was hited in previous tick*/;
OPL3 opl;
public:
static unsigned long ReadBEInt(const void* buffer, unsigned nbytes)
@@ -830,8 +836,11 @@ public:
CurrentPosition.track[tk].delay = ReadVarLen(tk);
}
}
- loopStart = true;
+ trackStart = true;
+ loopStart = true;
+ loopStart_passed = false;
invalidLoop = false;
+ loopStart_hit = false;
opl.Reset(); // Reset AdLib
//opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously)
@@ -1029,17 +1038,33 @@ private:
// ^HACK: CHRONO TRIGGER LOOP
*/
+ if(loopStart_hit && (loopStart||loopEnd)) //Avoid invalid loops
+ {
+ invalidLoop=true;
+ loopStart = false;
+ loopEnd = false;
+ LoopBeginPosition=trackBeginPosition;
+ } else {
+ loopStart_hit=false;
+ }
+
if(loopStart)
{
+ if(trackStart)
+ {
+ trackBeginPosition=RowBeginPosition;
+ trackStart=false;
+ }
LoopBeginPosition = RowBeginPosition;
loopStart = false;
+ loopStart_hit=true;
}
if(shortest < 0 || loopEnd)
{
// Loop if song end reached
loopEnd = false;
CurrentPosition = LoopBeginPosition;
- shortest = 0;
+ shortest = 0;
if(opl._parent->QuitWithoutLooping==1)
{
opl._parent->QuitFlag = 1;
@@ -1068,8 +1093,28 @@ private:
CurrentPosition.track[tk].ptr += length;
if(evtype == 0x2F) { CurrentPosition.track[tk].status = -1; return; }
if(evtype == 0x51) { Tempo = InvDeltaTicks * fraction<long>( (long) ReadBEInt(data.data(), data.size())); return; }
- if(evtype == 6 && data == "loopStart") loopStart = true;
- if(evtype == 6 && data == "loopEnd" ) loopEnd = true;
+ if(evtype == 6)
+ {
+ 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 == "loopend") && (!invalidLoop) )
+ {
+ if((loopStart_passed) && (!loopStart))
+ loopEnd=true;
+ else
+ invalidLoop=true;
+ }
+ }
if(evtype == 9) current_device[tk] = ChooseDevice(data);
// if(evtype >= 1 && evtype <= 6)
// UI.PrintLn("Meta %d: %s", evtype, data.c_str());
@@ -1801,47 +1846,6 @@ int adlRefreshNumCards(ADL_MIDIPlayer* device)
return 0;
}
-struct Mixx
-{
- static int requested_len; //size of target buffer
- static int stored_samples; //num of collected samples
- static int backup_samples[1024]; //Backup sample storage.
- static int backup_samples_size; //Backup sample storage.
- //If requested number of samples less than 512 bytes, backup will be stored
-
- static int *_len;
- static int *_out;
- static void SendStereoAudio(unsigned long count, int* samples)
- {
- if(!count) return;
- stored_samples=0;
- size_t pos=(*_len);
- for(unsigned long p = 0; p < count; ++p)
- for(unsigned w=0; w<2; ++w)
- {
- int out=samples[p*2+w];
- int offset=pos+p*2+w;
- if(offset<requested_len)
- _out[offset] = out;
- else
- {
- backup_samples[backup_samples_size]=out;
- backup_samples_size++; stored_samples++;
- }
- }
- }
-
-};
-
-int Mixx::requested_len=0;
-int Mixx::stored_samples=0;
-int Mixx::backup_samples[1024];
-int Mixx::backup_samples_size=0;
-int *Mixx::_len=NULL;
-int *Mixx::_out=NULL;
-
-
-
/*---------------------------EXPORTS---------------------------*/
ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate)
@@ -1863,6 +1867,10 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate)
_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;
+
_device->adl_midiPlayer = (void*)new MIDIplay;
((MIDIplay*)_device->adl_midiPlayer)->opl._parent=_device;
((MIDIplay*)_device->adl_midiPlayer)->opl.NumCards=_device->NumCards;
@@ -1872,7 +1880,7 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer* adl_init(long sample_rate)
((MIDIplay*)_device->adl_midiPlayer)->opl.HighVibratoMode=(bool)_device->HighVibratoMode;
((MIDIplay*)_device->adl_midiPlayer)->opl.AdlPercussionMode=(bool)_device->AdlPercussionMode;
((MIDIplay*)_device->adl_midiPlayer)->opl.ScaleModulators=(bool)_device->ScaleModulators;
- ((MIDIplay*)(_device->adl_midiPlayer))->ChooseDevice("");
+ ((MIDIplay*)(_device->adl_midiPlayer))->ChooseDevice("");
adlRefreshNumCards(_device);
return _device;
}
@@ -1961,9 +1969,10 @@ ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
{
- Mixx::backup_samples_size=0;
if(device && device->adl_midiPlayer)
{
+ device->stored_samples=0;
+ device->backup_samples_size=0;
if(!((MIDIplay *)device->adl_midiPlayer)->LoadMIDI(filePath))
{
ADLMIDI_ErrorString="ADL MIDI: Can't load file";
@@ -1976,9 +1985,10 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer* device, void *mem, long size)
{
- Mixx::backup_samples_size=0;
if(device && device->adl_midiPlayer)
{
+ device->stored_samples=0;
+ device->backup_samples_size=0;
if(!((MIDIplay *)device->adl_midiPlayer)->LoadMIDI(mem, size))
{
ADLMIDI_ErrorString="ADL MIDI: Can't load data from memory";
@@ -2003,8 +2013,10 @@ ADLMIDI_EXPORT const char *adl_getMusicTitle(ADL_MIDIPlayer *device)
ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device)
{
- Mixx::backup_samples_size=0;
- if(device->adl_midiPlayer) delete ((MIDIplay*)(device->adl_midiPlayer));
+ if(device->adl_midiPlayer)
+ {
+ delete ((MIDIplay*)(device->adl_midiPlayer));
+ }
device->adl_midiPlayer = NULL;
free(device);
device=NULL;
@@ -2013,42 +2025,73 @@ ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device)
ADLMIDI_EXPORT void adl_reset(ADL_MIDIPlayer *device)
{
if(!device) return;
- Mixx::backup_samples_size=0;
+ device->stored_samples=0;
+ device->backup_samples_size=0;
((MIDIplay*)device->adl_midiPlayer)->opl.Reset();
}
-ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out)
+inline static void SendStereoAudio(ADL_MIDIPlayer*device,
+ int& samples_requested,
+ unsigned long& in_size,
+ int* _in,
+ int out_pos,
+ short* _out)
+{
+ if(!in_size) return;
+ device->stored_samples=0;
+ int out;
+ int offset;
+ for(unsigned long p = 0; p < in_size; ++p)
+ {
+ for(unsigned w=0; w<2; ++w)
+ {
+ out = _in[p*2+w];
+ offset = out_pos+p*2+w;
+ if(offset<samples_requested)
+ {
+ _out[offset] = (short)out;
+ }
+ else
+ {
+ device->backup_samples[device->backup_samples_size]=out;
+ device->backup_samples_size++; device->stored_samples++;
+ }
+ }
+ }
+}
+
+
+ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, short *out)
{
if(!device) return 0;
+ sampleCount -= sampleCount%2;//Avoid non-odd sample requests
if(sampleCount<0) return 0;
if(device->QuitFlag) return 0;
int gotten_len=0;
- Mixx::requested_len=sampleCount;
- Mixx::_len=&gotten_len;
- Mixx::_out=out;
unsigned long n_samples=512;
unsigned long n_samples_2=n_samples*2;
- while(sampleCount>0)
+ int left = sampleCount;
+ while(left>0)
{
- if(Mixx::backup_samples_size>0)
+ if(device->backup_samples_size>0)
{ //Send reserved samples if exist
int ate=0;
- while((ate<Mixx::backup_samples_size) && (ate<sampleCount))
+ while((ate<device->backup_samples_size) && (ate<left))
{
- out[ate]=Mixx::backup_samples[ate]; ate++;
+ out[ate]=(short)device->backup_samples[ate]; ate++;
}
- sampleCount-=ate;
+ left-=ate;
gotten_len+=ate;
- if(ate<Mixx::backup_samples_size)
+ if(ate<device->backup_samples_size)
{
for(int j=0;
j<ate;
j++)
- Mixx::backup_samples[(ate-1)-j]=Mixx::backup_samples[(Mixx::backup_samples_size-1)-j];
+ device->backup_samples[(ate-1)-j]=device->backup_samples[(device->backup_samples_size-1)-j];
}
- Mixx::backup_samples_size-=ate;
+ device->backup_samples_size-=ate;
} else {
const double eat_delay = device->delay < device->maxdelay ? device->delay : device->maxdelay;
device->delay -= eat_delay;
@@ -2061,36 +2104,35 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out)
device->SkipForward -= 1;
else
{
- sampleCount-=n_samples_2;
+ left -= n_samples_2;
+ int buf[n_samples*2];
+ unsigned long in_count=n_samples;
+
if(device->NumCards == 1)
{
- ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[0].Generate(0, Mixx::SendStereoAudio, n_samples);
+ ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[0].GenerateArr(buf, &in_count);
+ /* Process it */
+ SendStereoAudio(device, sampleCount, in_count, buf, gotten_len, out);
}
else if(n_samples > 0)
{
- /* Mix together the audio from different cards */
- static std::vector<int> sample_buf;
- sample_buf.clear();
- sample_buf.resize(n_samples*2);
- struct Mix
- {
- static void AddStereoAudio(unsigned long count, int* samples)
- {
- for(unsigned long a=0; a<count*2; ++a)
- sample_buf[a] += samples[a];
- }
- };
+ int in[n_samples*2];
+
+ //fill buffer with zeros
+ for(unsigned long a=0; a<(in_count*2); ++a) buf[a] = 0;
+
+ unsigned long in_count = n_samples;
for(unsigned card = 0; card < device->NumCards; ++card)
{
- ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[card].Generate(
- 0,
- Mix::AddStereoAudio,
- n_samples);
+ ((MIDIplay*)(device->adl_midiPlayer))->opl.cards[card].GenerateArr( in, &in_count );
+ for(unsigned long a=0; a<(in_count*2); ++a)
+ buf[a] += in[a];
}
+
/* Process it */
- Mixx::SendStereoAudio(n_samples, &sample_buf[0]);
+ SendStereoAudio(device, sampleCount, in_count, buf, gotten_len, out);
}
- gotten_len += (n_samples*2)-Mixx::stored_samples;
+ gotten_len += (n_samples*2)-device->stored_samples;
}
device->delay = ((MIDIplay*)device->adl_midiPlayer)->Tick(eat_delay, device->mindelay);
}
@@ -2099,8 +2141,6 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer*device, int sampleCount, int *out)
}
-
-
#ifdef ADLMIDI_buildAsApp
int main(int argc, char** argv)
diff --git a/src/adlmidi.h b/src/adlmidi.h
index 75ae8a5..7e8bbd6 100644
--- a/src/adlmidi.h
+++ b/src/adlmidi.h
@@ -47,6 +47,12 @@ struct ADL_MIDIPlayer {
double mindelay;
double maxdelay;
+ /*For internal usage*/
+ int stored_samples; //num of collected samples
+ int backup_samples[1024]; //Backup sample storage.
+ int backup_samples_size; //Backup sample storage.
+ /*For internal usage*/
+
void *adl_midiPlayer;
unsigned long PCM_RATE;
};
@@ -94,7 +100,7 @@ extern void adl_reset(struct ADL_MIDIPlayer*device);
extern void adl_close(struct ADL_MIDIPlayer *device);
/*Take a sample buffer*/
-extern int adl_play(struct ADL_MIDIPlayer*device, int sampleCount, int out []);
+extern int adl_play(struct ADL_MIDIPlayer*device, int sampleCount, short out[]);
#ifdef __cplusplus
}