// utility function for OPL3 programming
/* These are offsets from the base I/O address. */
const int FM = 8; // SB (mono) ports (e.g. 228H and 229H)
const int PROFM1 = 0; // On CT-1330, this is left OPL-2. On CT-1600 and
// later cards, it's OPL-3 bank 0.
const int PROFM2 = 2; // On CT-1330, this is right OPL-2. On CT-1600 and
// later cards, it's OPL-3 bank 1.
void FMoutput(unsigned port, int reg, int val, std::shared_ptr<hardware::opl::OPL> opl)
/* This outputs a value to a specified FM register at a specified FM port. */
{
opl->write(port, reg); // OPL3_WriteRegBuffered
SDL_Delay(8);
opl->write(port + 1, val);
SDL_Delay(55);
}
void fm(int reg, int val, std::shared_ptr<hardware::opl::OPL> opl)
/* This function outputs a value to a specified FM register at the Sound
* Blaster (mono) port address.
*/
{
FMoutput(FM, reg, val, opl);
}
void Profm1(int reg, int val, std::shared_ptr<hardware::opl::OPL> opl)
/* This function outputs a value to a specified FM register at the Sound
* Blaster Pro left FM port address (or OPL-3 bank 0).
*/
{
FMoutput(PROFM1, reg, val, opl);
}
void Profm2(int reg, int val, std::shared_ptr<hardware::opl::OPL> opl)
/* This function outputs a value to a specified FM register at the Sound
* Blaster Pro right FM port address (or OPL-3 bank 1).
*/
{
FMoutput(PROFM2, reg, val, opl);
}
// ------------------------------------------
// snippet of the OPL3 programming
fm(1, 0, opl); /* must initialize this to zero */
Profm2(5, 1, opl); /* set to OPL3 mode, necessary for stereo */
fm(0xC0, LEFT | RIGHT | 1, opl); /* set both channels, parallel connection */
/***************************************
* Set parameters for the carrier cell *
***************************************/
fm(0x23, 0x21, opl); /* no amplitude modulation (D7=0), no vibrato (D6=0),
* sustained envelope type (D5=1), KSR=0 (D4=0),
* frequency multiplier=1 (D4-D0=1)
*/
fm(0x43, 0x0, opl); /* no volume decrease with pitch (D7-D6=0),
* no attenuation (D5-D0=0)
*/
fm(0x63, 0xff, opl); /* fast attack (D7-D4=0xF) and decay (D3-D0=0xF) */
fm(0x83, 0x05, opl); /* high sustain level (D7-D4=0), slow release rate (D3-D0=5) */
/*****************************************
* Set parameters for the modulator cell *
*****************************************/
fm(0x20, 0x20, opl); /* sustained envelope type, frequency multiplier=0 */
fm(0x40, 0x3f, opl); /* maximum attenuation, no volume decrease with pitch */
/* Since the modulator signal is attenuated as much as possible, these
* next two values shouldn't have any effect.
*/
fm(0x60, 0x44, opl); /* slow attack and decay */
fm(0x80, 0x05, opl); /* high sustain level, slow release rate */
/*************************************************
* Generate tone from values looked up in table. *
*************************************************/
spdlog::info("440 Hz tone, values looked up in table.");
fm(0xa0, 0x41, opl); /* 440 Hz */
fm(0xb0, 0x32, opl); /* 440 Hz, block 0, key on */
SDL_Delay(1000);
fm(0xb0, 0x12, opl); /* key off */
the resulting sound is not a continuos wave 440Hz but is randomly not generated properly resulting in a clipped/noise sound.
Same script used with a DosBox OPL3 emulation instead have the right expected results.