void OPLmusicFile::Dump() { int time; time = PlayTick(); while (time != 0) { io->WriteDelay(time); time = PlayTick(); } }
int OPLDumperMIDIDevice::Resume() { int time; time = PlayTick(); while (time != 0) { io->WriteDelay(time); time = PlayTick(); } return 0; }
bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { float *samples1 = (float *)buff; int stereoshift = (int)(FullPan | io->IsOPL3); int numsamples = numbytes / (sizeof(float) << stereoshift); bool prevEnded = false; bool res = true; memset(buff, 0, numbytes); ChipAccess.Enter(); while (numsamples > 0) { double ticky = NextTickIn; int tick_in = int(NextTickIn); int samplesleft = MIN(numsamples, tick_in); size_t i; if (samplesleft > 0) { for (i = 0; i < io->NumChips; ++i) { io->chips[i]->Update(samples1, samplesleft); } OffsetSamples(samples1, samplesleft << stereoshift); assert(NextTickIn == ticky); NextTickIn -= samplesleft; assert (NextTickIn >= 0); numsamples -= samplesleft; samples1 += samplesleft << stereoshift; } if (NextTickIn < 1) { int next = PlayTick(); assert(next >= 0); if (next == 0) { // end of song if (!Looping || prevEnded) { if (numsamples > 0) { for (i = 0; i < io->NumChips; ++i) { io->chips[i]->Update(samples1, numsamples); } OffsetSamples(samples1, numsamples << stereoshift); } res = false; break; } else { // Avoid infinite loops from songs that do nothing but end prevEnded = true; Restart (); } } else { prevEnded = false; io->WriteDelay(next); NextTickIn += SamplesPerTick * next; assert (NextTickIn >= 0); MLtime += next; } } } ChipAccess.Leave(); return res; }
bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { short *samples = (short *)buff; int *samples1 = SampleBuff; int numsamples = numbytes / 2; bool prevEnded = false; bool res = true; memset (SampleBuff, 0, numsamples * 4); #ifdef _WIN32 EnterCriticalSection (&ChipAccess); #else if (SDL_mutexP (ChipAccess) != 0) return true; #endif while (numsamples > 0) { int samplesleft = MIN (numsamples, NextTickIn); if (samplesleft > 0) { YM3812UpdateOne (0, samples1, samplesleft); if (TwoChips) { YM3812UpdateOne (1, samples1, samplesleft); } NextTickIn -= samplesleft; assert (NextTickIn >= 0); numsamples -= samplesleft; samples1 += samplesleft; } if (NextTickIn == 0) { int next = PlayTick (); if (next == 0) { // end of song if (!Looping || prevEnded) { if (numsamples > 0) { YM3812UpdateOne (0, samples1, numsamples); if (TwoChips) { YM3812UpdateOne (1, samples1, numsamples); } } res = false; break; } else { // Avoid infinite loops from songs that do nothing but end prevEnded = true; Restart (); } } else { prevEnded = false; NextTickIn = SamplesPerTick * next; assert (NextTickIn >= 0); MLtime += next; } } } #ifdef _WIN32 LeaveCriticalSection (&ChipAccess); #else SDL_mutexV (ChipAccess); #endif numsamples = numbytes / 2; samples1 = SampleBuff; #if defined(_MSC_VER) && defined(USEASM) if (CPU.bCMOV && numsamples > 1) { __asm { mov ecx, numsamples mov esi, samples1 mov edi, samples shr ecx, 1 lea esi, [esi+ecx*8] lea edi, [edi+ecx*4] neg ecx mov edx, 0x00007fff looper: mov eax, [esi+ecx*8] mov ebx, [esi+ecx*8+4] // Shift the samples down to reduce the chance of clipping at the high end. // Since most of the waveforms we produce only use the upper half of the // sine wave, this is a good thing. Although it does leave less room at // the bottom of the sine before clipping, almost none of the songs I tested // went below -9000. sub eax, 18000 sub ebx, 18000 // Clamp high cmp eax, edx cmovg eax, edx cmp ebx, edx cmovg ebx, edx // Clamp low not edx cmp eax, edx cmovl eax, edx cmp ebx, edx cmovl ebx, edx not edx mov [edi+ecx*4], ax mov [edi+ecx*4+2], bx inc ecx jnz looper test numsamples, 1 jz done mov eax, [esi+ecx*8] sub eax, 18000 cmp eax, edx cmovg eax, edx not edx cmp eax, edx cmovl eax, edx mov [edi+ecx*2], ax done: } }