From 8452f0131015e4778f048eabb744be8d3d413ac6 Mon Sep 17 00:00:00 2001 From: terminx Date: Sat, 7 Dec 2019 23:49:33 +0000 Subject: [PATCH] A small amount of driver_adlib cleanup git-svn-id: https://svn.eduke32.com/eduke32@8361 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # platform/Windows/audiolib.vcxproj # platform/Windows/audiolib.vcxproj.filters # source/audiolib/src/driver_adlib.cpp # source/audiolib/src/driver_adlib.h # source/audiolib/src/fx_man.cpp --- source/audiolib/include/al_midi.h | 2 +- source/audiolib/include/opl3_reg.h | 144 +++++++++++++++++++++++++++ source/audiolib/src/driver_adlib.cpp | 129 ++++++++++++------------ source/audiolib/src/driver_adlib.h | 1 + source/audiolib/src/midi.cpp | 4 +- 5 files changed, 209 insertions(+), 71 deletions(-) create mode 100644 source/audiolib/include/opl3_reg.h diff --git a/source/audiolib/include/al_midi.h b/source/audiolib/include/al_midi.h index f49d6058a..1dbb1608a 100644 --- a/source/audiolib/include/al_midi.h +++ b/source/audiolib/include/al_midi.h @@ -39,7 +39,7 @@ typedef struct extern AdLibTimbre ADLIB_TimbreBank[256]; opl3_chip *AL_GetChip(void); -void AL_RegisterTimbreBank(uint8_t *timbres); +void AL_RegisterTimbreBank(uint8_t const *timbres); void AL_SetStereo(int const stereo); #endif diff --git a/source/audiolib/include/opl3_reg.h b/source/audiolib/include/opl3_reg.h new file mode 100644 index 000000000..2396706d6 --- /dev/null +++ b/source/audiolib/include/opl3_reg.h @@ -0,0 +1,144 @@ +/* + * Copyright by Hannu Savolainen 1993-1996 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// heavily modified for audiolib +// original definitions found at http://www.cs.albany.edu/~sdc/Linux/linux-2.0/drivers/sound/opl3.h +// it's from old Linux source but the license is pretty clearly 2-clause BSD. + +#ifndef opl3_reg_h__ +#define OPL3_opl3_reg_h__ + +#define OPL3_TEST_REGISTER 0x01 +#define OPL3_ENABLE_WAVE_SELECT 0x20 + +#define OPL3_TIMER1_REGISTER 0x02 +#define OPL3_TIMER2_REGISTER 0x03 +#define OPL3_TIMER_CONTROL_REGISTER 0x04 /* Left side */ +#define OPL3_IRQ_RESET 0x80 +#define OPL3_TIMER1_MASK 0x40 +#define OPL3_TIMER2_MASK 0x20 +#define OPL3_TIMER1_START 0x01 +#define OPL3_TIMER2_START 0x02 + +#define OPL3_CONNECTION_SELECT_REGISTER 0x04 /* Right side */ +#define OPL3_RIGHT_4OP_0 0x01 +#define OPL3_RIGHT_4OP_1 0x02 +#define OPL3_RIGHT_4OP_2 0x04 +#define OPL3_LEFT_4OP_0 0x08 +#define OPL3_LEFT_4OP_1 0x10 +#define OPL3_LEFT_4OP_2 0x20 + +#define OPL3_MODE_REGISTER 0x05 /* Right side */ +#define OPL3_ENABLE 0x01 +#define OPL3_OPL4_ENABLE 0x02 + +#define OPL3_KBD_SPLIT_REGISTER 0x08 /* Left side */ +#define OPL3_COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ +#define OPL3_KEYBOARD_SPLIT 0x40 + +#define OPL3_PERCUSSION_REGISTER 0xbd /* Left side only */ +#define OPL3_TREMOLO_DEPTH 0x80 +#define OPL3_VIBRATO_DEPTH 0x40 +#define OPL3_PERCUSSION_ENABLE 0x20 +#define OPL3_BASSDRUM_ON 0x10 +#define OPL3_SNAREDRUM_ON 0x08 +#define OPL3_TOMTOM_ON 0x04 +#define OPL3_CYMBAL_ON 0x02 +#define OPL3_HIHAT_ON 0x01 + +/* + * Offsets to the register banks for operators. To get the + * register number just add the operator offset to the bank offset + * + * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) + */ +#define OPL3_AM_VIB 0x20 +#define OPL3_TREMOLO_ON 0x80 +#define OPL3_VIBRATO_ON 0x40 +#define OPL3_SUSTAIN_ON 0x20 +#define OPL3_KSR 0x10 /* Key scaling rate */ +#define OPL3_MULTIPLE_MASK 0x0f /* Frequency multiplier */ + +/* + * KSL/Total level (0x40 to 0x55) + */ +#define OPL3_KSL_LEVEL 0x40 +#define OPL3_KSL_MASK 0xc0 /* Envelope scaling bits */ +#define OPL3_TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ + +/* + * Attack / Decay rate (0x60 to 0x75) + */ +#define OPL3_ATTACK_DECAY 0x60 +#define OPL3_ATTACK_MASK 0xf0 +#define OPL3_DECAY_MASK 0x0f + +/* + * Sustain level / Release rate (0x80 to 0x95) + */ +#define OPL3_SUSTAIN_RELEASE 0x80 +#define OPL3_SUSTAIN_MASK 0xf0 +#define OPL3_RELEASE_MASK 0x0f + +/* + * Wave select (0xE0 to 0xF5) + */ +#define OPL3_WAVE_SELECT 0xe0 + +/* + * Offsets to the register banks for voices. Just add to the + * voice number to get the register number. + * + * F-Number low bits (0xA0 to 0xA8). + */ +#define OPL3_FNUM_LOW 0xa0 + +/* + * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) + */ +#define OPL3_KEYON_BLOCK 0xb0 +#define OPL3_KEYON_BIT 0x20 +#define OPL3_BLOCKNUM_MASK 0x1c +#define OPL3_FNUM_HIGH_MASK 0x03 + +/* + * Feedback / Connection (0xc0 to 0xc8) + * + * These registers have two new bits when the OPL-3 mode + * is selected. These bits controls connecting the voice + * to the stereo channels. For 4 OP voices this bit is + * defined in the second half of the voice (add 3 to the + * register offset). + * + * For 4 OP voices the connection bit is used in the + * both halfs (gives 4 ways to connect the operators). + */ +#define OPL3_FEEDBACK_CONNECTION 0xc0 +#define OPL3_FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ +#define OPL3_CONNECTION_BIT 0x01 +#define OPL3_STEREO_BITS 0x30 /* OPL-3 only */ +#define OPL3_VOICE_TO_LEFT 0x10 +#define OPL3_VOICE_TO_RIGHT 0x20 + +#endif // opl3_reg_h__ diff --git a/source/audiolib/src/driver_adlib.cpp b/source/audiolib/src/driver_adlib.cpp index 599601ec8..aefb10bc5 100644 --- a/source/audiolib/src/driver_adlib.cpp +++ b/source/audiolib/src/driver_adlib.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "midi.h" #include "midifuncs.h" #include "opl3.h" +#include "opl3_reg.h" #include "c_cvars.h" CUSTOM_CVARD(Bool, mus_al_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG, "enable/disable OPL3 stereo mode") @@ -127,7 +128,7 @@ static opl3_chip chip; opl3_chip *AL_GetChip(void) { return &chip; } -static constexpr uint32_t OctavePitch[MAX_OCTAVE+1] = { +static uint32_t constexpr OctavePitch[MAX_OCTAVE+1] = { OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3, OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7, }; @@ -141,7 +142,7 @@ static uint32_t NoteDiv12[MAX_NOTE+1]; // { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B }, // }; -static constexpr uint32_t NotePitch[FINETUNE_MAX+1][12] = { +static uint32_t constexpr NotePitch[FINETUNE_MAX+1][12] = { { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 }, { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 }, { 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 }, @@ -179,7 +180,7 @@ static constexpr uint32_t NotePitch[FINETUNE_MAX+1][12] = { // Slot numbers as a function of the voice and the operator. // ( melodic only) -static constexpr int slotVoice[NUMADLIBVOICES][2] = { +static int constexpr slotVoice[NUMADLIBVOICES][2] = { { 0, 3 }, // voice 0 { 1, 4 }, // 1 { 2, 5 }, // 2 @@ -197,7 +198,7 @@ static int VoiceKsl[AL_NumChipSlots][2]; // This table gives the offset of each slot within the chip. // offset = fn( slot) -static constexpr int8_t offsetSlot[AL_NumChipSlots] = { 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 }; +static int8_t constexpr offsetSlot[AL_NumChipSlots] = { 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 }; static int VoiceReserved[NUMADLIBVOICES * 2]; @@ -206,10 +207,14 @@ static AdLibVoiceList Voice_Pool; static AdLibChannel Channel[NUMADLIBCHANNELS]; -static int AL_LeftPort = ADLIB_PORT; -static int AL_RightPort = ADLIB_PORT; +static int constexpr AL_LeftPort = ADLIB_PORT; +static int constexpr AL_RightPort = ADLIB_PORT + 2; + +static int constexpr AL_MaxMidiChannel = ARRAY_SIZE(Channel); + int AL_Stereo = TRUE; -static int AL_MaxMidiChannel = 16; + +int AL_PostAmp = 3; // TODO: clean up this shit... #define OFFSET(structure, offset) (*((char **)&(structure)[offset])) @@ -260,8 +265,7 @@ static void AL_SendOutputToPort(int const port, int const reg, int const data) static void AL_SendOutput(int const voice, int const reg, int const data) { - int port = (voice == 0) ? AL_RightPort : AL_LeftPort; - AL_SendOutputToPort(port, reg, data); + AL_SendOutputToPort(voice ? AL_LeftPort : AL_RightPort, reg, data); } @@ -282,39 +286,39 @@ static void AL_SetVoiceTimbre(int const voice) int slot = slotVoice[voc][0]; int off = offsetSlot[slot]; - VoiceLevel[slot][port] = 63 - (timbre->Level[0] & 0x3f); - VoiceKsl[slot][port] = timbre->Level[0] & 0xc0; + VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[0] & OPL3_TOTAL_LEVEL_MASK); + VoiceKsl[slot][port] = timbre->Level[0] & OPL3_KSL_MASK; - AL_SendOutput(port, 0xA0 + voc, 0); - AL_SendOutput(port, 0xB0 + voc, 0); + AL_SendOutput(port, OPL3_FNUM_LOW + voc, 0); + AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, 0); // Let voice clear the release - AL_SendOutput(port, 0x80 + off, 0xff); + AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff); - AL_SendOutput(port, 0x60 + off, timbre->Env1[0]); - AL_SendOutput(port, 0x80 + off, timbre->Env2[0]); - AL_SendOutput(port, 0x20 + off, timbre->SAVEK[0]); - AL_SendOutput(port, 0xE0 + off, timbre->Wave[0]); + AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[0]); + AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[0]); + AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[0]); + AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[0]); - AL_SendOutput(port, 0x40 + off, timbre->Level[0]); + AL_SendOutput(port, OPL3_KSL_LEVEL + off, timbre->Level[0]); slot = slotVoice[voc][1]; - AL_SendOutput(port, 0xC0 + voc, (timbre->Feedback & 0x0f) | 0x30); + AL_SendOutput(port, OPL3_FEEDBACK_CONNECTION + voc, (timbre->Feedback & OPL3_FEEDBACK_MASK) | OPL3_STEREO_BITS); off = offsetSlot[slot]; - VoiceLevel[slot][port] = 63 - (timbre->Level[1] & 0x3f); - VoiceKsl[slot][port] = timbre->Level[1] & 0xc0; + VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[1] & OPL3_TOTAL_LEVEL_MASK); + VoiceKsl[slot][port] = timbre->Level[1] & OPL3_KSL_MASK; - AL_SendOutput(port, 0x40 + off, 63); + AL_SendOutput(port, OPL3_KSL_LEVEL + off, OPL3_TOTAL_LEVEL_MASK); // Let voice clear the release - AL_SendOutput(port, 0x80 + off, 0xff); + AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff); - AL_SendOutput(port, 0x60 + off, timbre->Env1[1]); - AL_SendOutput(port, 0x80 + off, timbre->Env2[1]); - AL_SendOutput(port, 0x20 + off, timbre->SAVEK[1]); - AL_SendOutput(port, 0xE0 + off, timbre->Wave[1]); + AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[1]); + AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[1]); + AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[1]); + AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[1]); } @@ -332,10 +336,10 @@ static void AL_SetVoiceVolume(int const voice) auto t1 = (uint32_t)VoiceLevel[slot][port] * (velocity + 0x80); t1 = (Channel[channel].Volume * t1) >> 15; - uint32_t volume = t1 ^ 63; + uint32_t volume = t1 ^ OPL3_TOTAL_LEVEL_MASK; volume |= (uint32_t)VoiceKsl[slot][port]; - AL_SendOutput(port, 0x40 + offsetSlot[slot], volume); + AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume); // Check if this timbre is Additive if (timbre->Feedback & 0x01) @@ -349,24 +353,22 @@ static void AL_SetVoiceVolume(int const voice) t2 = (Channel[channel].Volume * t1) >> 15; - volume = t2 ^ 63; + volume = t2 ^ OPL3_TOTAL_LEVEL_MASK; volume |= (uint32_t)VoiceKsl[slot][port]; - AL_SendOutput(port, 0x40 + offsetSlot[slot], volume); + AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume); } } static int AL_AllocVoice(void) { - if (Voice_Pool.start) - { + if (!Voice_Pool.start) + return AL_VoiceNotFound; + int const voice = Voice_Pool.start->num; LL_Remove(AdLibVoice, &Voice_Pool, &Voice[voice]); return voice; - } - - return AL_VoiceNotFound; } @@ -418,8 +420,8 @@ static void AL_SetVoicePitch(int const voice) pitch |= Voice[voice].status; - AL_SendOutput(port, 0xA0 + voc, pitch); - AL_SendOutput(port, 0xB0 + voc, pitch >> 8); + AL_SendOutput(port, OPL3_FNUM_LOW + voc, pitch); + AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, pitch >> 8); } static void AL_SetVoicePan(int const voice) @@ -531,32 +533,32 @@ static void AL_FlushCard(int const port) auto slot1 = offsetSlot[slotVoice[i][0]]; auto slot2 = offsetSlot[slotVoice[i][1]]; - AL_SendOutputToPort(port, 0xA0 + i, 0); - AL_SendOutputToPort(port, 0xB0 + i, 0); + AL_SendOutputToPort(port, OPL3_FNUM_LOW + i, 0); + AL_SendOutputToPort(port, OPL3_KEYON_BLOCK + i, 0); - AL_SendOutputToPort(port, 0xE0 + slot1, 0); - AL_SendOutputToPort(port, 0xE0 + slot2, 0); + AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot1, 0); + AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot2, 0); // Set the envelope to be fast and quiet - AL_SendOutputToPort(port, 0x60 + slot1, 0xff); - AL_SendOutputToPort(port, 0x60 + slot2, 0xff); - AL_SendOutputToPort(port, 0x80 + slot1, 0xff); - AL_SendOutputToPort(port, 0x80 + slot2, 0xff); + AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot1, 0xff); + AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot2, 0xff); + AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot1, 0xff); + AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot2, 0xff); // Maximum attenuation - AL_SendOutputToPort(port, 0x40 + slot1, 0xff); - AL_SendOutputToPort(port, 0x40 + slot2, 0xff); + AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot1, 0xff); + AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot2, 0xff); } } static void AL_Reset(void) { - AL_SendOutputToPort(ADLIB_PORT, 1, 0x20); - AL_SendOutputToPort(ADLIB_PORT, 0x08, 0); + AL_SendOutputToPort(ADLIB_PORT, 1, OPL3_ENABLE_WAVE_SELECT); + AL_SendOutputToPort(ADLIB_PORT, OPL3_KBD_SPLIT_REGISTER, 0); // Set the values: AM Depth, VIB depth & Rhythm - AL_SendOutputToPort(ADLIB_PORT, 0xBD, 0); + AL_SendOutputToPort(ADLIB_PORT, OPL3_PERCUSSION_REGISTER, 0); AL_SetStereo(AL_Stereo); @@ -565,10 +567,7 @@ static void AL_Reset(void) } -void AL_SetStereo(int const stereo) -{ - AL_SendOutputToPort(AL_RightPort, 0x5, (stereo<<1)+1); -} +void AL_SetStereo(int const stereo) { AL_SendOutputToPort(AL_RightPort, OPL3_MODE_REGISTER, (stereo << 1) + 1); } static void AL_NoteOff(int const channel, int const key, int velocity) @@ -579,17 +578,17 @@ static void AL_NoteOff(int const channel, int const key, int velocity) if (channel > AL_MaxMidiChannel) return; - int voice = AL_GetVoice(channel, key); + int const voice = AL_GetVoice(channel, key); if (voice == AL_VoiceNotFound) return; Voice[voice].status = NOTE_OFF; - int port = Voice[voice].port; - int voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice; + int const port = Voice[voice].port; + int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice; - AL_SendOutput(port, 0xB0 + voc, hibyte(Voice[voice].pitchleft)); + AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, hibyte(Voice[voice].pitchleft)); LL_Remove(AdLibVoice, &Channel[channel].Voices, &Voice[voice]); LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[voice]); @@ -720,12 +719,9 @@ static void AL_SetPitchBend(int const channel, int const lsb, int const msb) return; int const pitchbend = lsb + (msb << 8); + int const TotalBend = pitchbend * Channel[channel].PitchBendRange / (PITCHBEND_CENTER / FINETUNE_RANGE); Channel[channel].Pitchbend = pitchbend; - - int TotalBend = pitchbend * Channel[channel].PitchBendRange; - TotalBend /= (PITCHBEND_CENTER / FINETUNE_RANGE); - Channel[channel].KeyOffset = (int)(TotalBend / FINETUNE_RANGE); Channel[channel].KeyOffset -= Channel[channel].PitchBendSemiTones; @@ -751,9 +747,6 @@ static int AL_Init(int const rate) { OPL3_Reset(&chip, rate); - AL_LeftPort = ADLIB_PORT; - AL_RightPort = ADLIB_PORT + 2; - AL_CalcPitchInfo(); AL_Reset(); AL_ResetVoices(); @@ -762,7 +755,7 @@ static int AL_Init(int const rate) } -void AL_RegisterTimbreBank(uint8_t *timbres) +void AL_RegisterTimbreBank(uint8_t const *timbres) { for (int i = 0; i < 256; i++) { diff --git a/source/audiolib/src/driver_adlib.h b/source/audiolib/src/driver_adlib.h index 1ddd90544..198d84ae8 100644 --- a/source/audiolib/src/driver_adlib.h +++ b/source/audiolib/src/driver_adlib.h @@ -23,6 +23,7 @@ #include "opl3.h" extern int AL_Stereo; +extern int AL_PostAmp; int AdLibDrv_GetError(void); const char *AdLibDrv_ErrorString(int ErrorNumber); diff --git a/source/audiolib/src/midi.cpp b/source/audiolib/src/midi.cpp index 5347c74e4..cef907974 100644 --- a/source/audiolib/src/midi.cpp +++ b/source/audiolib/src/midi.cpp @@ -538,8 +538,8 @@ static void _MIDI_ServiceMultivoc(void) } if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo; OPL3_GenerateResampled(AL_GetChip(), buf); - *buffer16++ = clamp(buf[0]<<3, INT16_MIN, INT16_MAX); - *buffer16++ = clamp(buf[1]<<3, INT16_MIN, INT16_MAX); + *buffer16++ = clamp(buf[0]<