From 8f49ea7f48e3fd94101820b1790736f12d91044b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 29 Mar 2008 01:30:37 +0000 Subject: [PATCH] - Changed the output of the OPL emulator from 32-bit integers to 32-bit floats, so I can write its output directly to the stream buffer. In addition, this lets me bring the OPL volume level much closer to the standard MIDI volume. SVN r863 (trunk) --- src/oplsynth/fmopl.cpp | 93 ++----------------------- src/oplsynth/fmopl.h | 2 +- src/oplsynth/opl_mus_player.cpp | 106 ++--------------------------- src/oplsynth/opl_mus_player.h | 3 - src/sound/fmodsound.cpp | 19 +++++- src/sound/fmodsound.h | 2 - src/sound/i_sound.h | 4 +- src/sound/music_mus_opl.cpp | 6 +- src/sound/music_win_mididevice.cpp | 4 +- 9 files changed, 37 insertions(+), 202 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index b333338e6..7928a3134 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -583,7 +583,7 @@ static signed int output[1]; static UINT32 LFO_AM; static INT32 LFO_PM; -static bool CalcVoice (FM_OPL *OPL, int voice, INT32 *buffer, int length); +static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length); @@ -782,70 +782,8 @@ INLINE void advance(FM_OPL *OPL) } -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - UINT32 p; - INT32 i; - - i = (phase & ~FREQ_MASK) + pm; - -/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ - - p = (env<<4) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; - -/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - - #define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) -/* calculate output */ -INLINE void OPL_CALC_CH( OPL_CH *CH ) -{ - OPL_SLOT *SLOT; - unsigned int env; - signed int out; - - phase_modulation = 0; - - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env = volume_calc(SLOT); - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - *SLOT->connect1 += SLOT->op1_out[0]; - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - { - output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); - } -} - /* generic table initialize */ static int init_tables(void) { @@ -1608,33 +1546,15 @@ void YM3812SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) ** '*buffer' is the output buffer pointer ** 'length' is the number of samples that should be generated */ -void YM3812UpdateOne(int which, INT32 *buffer, int length) +void YM3812UpdateOne(int which, float *buffer, int length) { FM_OPL *OPL = OPL_YM3812[which]; - INT32 *buf = buffer; int i; if( (void *)OPL != cur_chip ) { cur_chip = (void *)OPL; } -#if 0 - for( i=0; i < length ; i++ ) - { - output[0] = 0; - - advance_lfo(OPL); - - /* FM part */ - for (int j = 0; j <= 8; ++j) - { - OPL_CALC_CH(&OPL->P_CH[j]); - } - // [RH] Just add to the output. Clamping will happen later. - buf[i] += output[0]; - advance(OPL); - } -#else UINT32 lfo_am_cnt_bak = OPL->lfo_am_cnt; UINT32 eg_timer_bak = OPL->eg_timer; UINT32 eg_cnt_bak = OPL->eg_cnt; @@ -1648,7 +1568,7 @@ void YM3812UpdateOne(int which, INT32 *buffer, int length) OPL->lfo_am_cnt = lfo_am_cnt_bak; OPL->eg_timer = eg_timer_bak; OPL->eg_cnt = eg_cnt_bak; - if (CalcVoice (OPL, i, buf, length)) + if (CalcVoice (OPL, i, buffer, length)) { lfo_am_cnt_out = OPL->lfo_am_cnt; eg_timer_out = OPL->eg_timer; @@ -1659,13 +1579,12 @@ void YM3812UpdateOne(int which, INT32 *buffer, int length) OPL->lfo_am_cnt = lfo_am_cnt_out; OPL->eg_timer = eg_timer_out; OPL->eg_cnt = eg_cnt_out; -#endif } // [RH] Render a whole voice at once. If nothing else, it lets us avoid // wasting a lot of time on voices that aren't playing anything. -static bool CalcVoice (FM_OPL *OPL, int voice, INT32 *buffer, int length) +static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length) { OPL_CH *const CH = &OPL->P_CH[voice]; int i, j; @@ -1729,8 +1648,8 @@ static bool CalcVoice (FM_OPL *OPL, int voice, INT32 *buffer, int length) { output[0] += tl_tab[p]; } - // [RH] make the output louder. - buffer[i] += (output[0] + (output[0]>>1)); + // [RH] Convert to floating point. + buffer[i] += float(output[0]) / 7168.f; } // advance diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h index 22b6bb0e6..464026519 100644 --- a/src/oplsynth/fmopl.h +++ b/src/oplsynth/fmopl.h @@ -38,7 +38,7 @@ void YM3812ResetChip(int which); int YM3812Write(int which, int a, int v); unsigned char YM3812Read(int which, int a); int YM3812TimerOver(int which, int c); -void YM3812UpdateOne(int which, INT32 *buffer, int length); +void YM3812UpdateOne(int which, float *buffer, int length); void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index cd5cdd09e..3fde91a2d 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -24,8 +24,6 @@ static OPLmusicBlock *BlockForStats; OPLmusicBlock::OPLmusicBlock() { scoredata = NULL; - SampleBuff = NULL; - SampleBuffSize = 0; NextTickIn = 0; TwoChips = !opl_onechip; Looping = false; @@ -45,11 +43,6 @@ OPLmusicBlock::OPLmusicBlock() OPLmusicBlock::~OPLmusicBlock() { BlockForStats = NULL; - if (SampleBuff != NULL) - { - delete[] SampleBuff; - SampleBuff = NULL; - } #ifdef _WIN32 DeleteCriticalSection (&ChipAccess); #else @@ -227,23 +220,14 @@ void OPLmusicFile::Restart () bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { - short *samples = (short *)buff; - int *samples1; - int numsamples = numbytes / 2; + float *samples = (float *)buff; + float *samples1; + int numsamples = numbytes / sizeof(float); bool prevEnded = false; bool res = true; - // SampleBuff is allocated here, since FMOD might not give us exactly - // the buffer size we requested. (Actually, it's giving us twice what - // was asked for. Am I doing something wrong?) - numbytes = numsamples * sizeof(int); - if (SampleBuff == NULL || numbytes > SampleBuffSize) - { - SampleBuff = (int *)M_Realloc(SampleBuff, numbytes); - SampleBuffSize = numbytes; - } - memset(SampleBuff, 0, numbytes); - samples1 = SampleBuff; + samples1 = samples; + memset(buff, 0, numbytes); #ifdef _WIN32 EnterCriticalSection (&ChipAccess); @@ -307,86 +291,6 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) #else SDL_mutexV (ChipAccess); #endif - numsamples = numbytes / sizeof(int); - 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: - } - } - else -#endif - { - for (int i = 1; i < numsamples; i+=2) - { - int u = samples1[i-1] - 18000; - int v = samples1[i ] - 18000; - if (u < -32768) u = -32768; else if (u > 32767) u = 32767; - if (v < -32768) v = -32768; else if (v > 32767) v = 32767; - samples[i-1] = u; - samples[i ] = v; - } - if (numsamples & 1) - { - int v = samples1[numsamples-1] - 18000; - if (v < -32768) v = -32768; else if (v > 32767) v = 32767; - samples[numsamples-1] = v; - } - } return res; } diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index 090345673..30cc6f1ba 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -30,9 +30,6 @@ protected: bool TwoChips; bool Looping; - int *SampleBuff; - int SampleBuffSize; - #ifdef _WIN32 CRITICAL_SECTION ChipAccess; #else diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index c918cff33..48cea0486 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -945,7 +945,7 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int capsule = new FMODStreamCapsule (userdata, callback, this); mode = FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_SOFTWARE | FMOD_CREATESTREAM | FMOD_OPENONLY; - sample_shift = (flags & SoundStream::Bits8) ? 0 : 1; + sample_shift = (flags & (SoundStream::Bits32 | SoundStream::Float)) ? 2 : (flags & SoundStream::Bits8) ? 0 : 1; channel_shift = (flags & SoundStream::Mono) ? 0 : 1; // Chunk size of stream update in samples. This will be the amount of data @@ -963,7 +963,22 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int exinfo.defaultfrequency = samplerate; // Data format of sound. - exinfo.format = (flags & SoundStream::Bits8) ? FMOD_SOUND_FORMAT_PCM8 : FMOD_SOUND_FORMAT_PCM16; + if (flags & SoundStream::Float) + { + exinfo.format = FMOD_SOUND_FORMAT_PCMFLOAT; + } + else if (flags & SoundStream::Bits32) + { + exinfo.format = FMOD_SOUND_FORMAT_PCM32; + } + else if (flags & SoundStream::Bits8) + { + exinfo.format = FMOD_SOUND_FORMAT_PCM8; + } + else + { + exinfo.format = FMOD_SOUND_FORMAT_PCM16; + } // User callback for reading. exinfo.pcmreadcallback = FMODStreamCapsule::PCMReadCallback; diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 9630cfc95..19cc72650 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -49,8 +49,6 @@ public: void ResetEnvironment (); private: - unsigned int DriverCaps; - int OutputType; bool SFXPaused; bool InitSuccess; diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index ad36ce5ba..2e4a7e081 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -46,9 +46,11 @@ public: { // For CreateStream Mono = 1, Bits8 = 2, + Bits32 = 4, + Float = 8, // For OpenStream - Loop = 4 + Loop = 16 }; virtual bool Play (bool looping, float volume, bool normalize) = 0; diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 176abe800..f6948f93d 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -19,8 +19,8 @@ OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len) Music = new OPLmusicFile (file, musiccache, len, samples); - m_Stream = GSnd->CreateStream (FillStream, samples*2, - SoundStream::Mono, int(OPL_SAMPLE_RATE), this); + m_Stream = GSnd->CreateStream (FillStream, samples*4, + SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); @@ -63,7 +63,7 @@ void OPLMUSSong::Play (bool looping) Music->SetLooping (looping); Music->Restart (); - if (m_Stream->Play (true, snd_musicvolume, true)) + if (m_Stream->Play (true, snd_musicvolume, false)) { m_Status = STATE_Playing; } diff --git a/src/sound/music_win_mididevice.cpp b/src/sound/music_win_mididevice.cpp index 69f3cca97..fb4f7378f 100644 --- a/src/sound/music_win_mididevice.cpp +++ b/src/sound/music_win_mididevice.cpp @@ -1,6 +1,6 @@ /* -** music_mididevice.cpp -** Provides a WinMM implementation of a generic MIDI output device. +** music_win_mididevice.cpp +** Provides a WinMM implementation of a MIDI output device. ** **--------------------------------------------------------------------------- ** Copyright 2008 Randy Heit