diff --git a/source/audiolib/include/drivers.h b/source/audiolib/include/drivers.h index 1a86afe43..1026e8175 100644 --- a/source/audiolib/include/drivers.h +++ b/source/audiolib/include/drivers.h @@ -25,8 +25,8 @@ #include "midifuncs.h" extern int ASS_PCMSoundDriver; -extern int ASS_CDSoundDriver; extern int ASS_MIDISoundDriver; +extern int ASS_EMIDICard; int SoundDriver_IsPCMSupported(int driver); int SoundDriver_IsMIDISupported(int driver); diff --git a/source/audiolib/include/fx_man.h b/source/audiolib/include/fx_man.h index 96e088c51..b4f791704 100644 --- a/source/audiolib/include/fx_man.h +++ b/source/audiolib/include/fx_man.h @@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define FX_MAN_H_ #include "drivers.h" -#include "inttypes.h" +#include #include "limits.h" #include "multivoc.h" diff --git a/source/audiolib/include/music.h b/source/audiolib/include/music.h index 2fe05e91b..b75d2da2f 100644 --- a/source/audiolib/include/music.h +++ b/source/audiolib/include/music.h @@ -61,15 +61,15 @@ typedef struct extern const char *MUSIC_ErrorString(int ErrorNumber); -int MUSIC_Init(int SoundCard); -int MUSIC_Shutdown(void); -void MUSIC_SetVolume(int volume); -int MUSIC_GetVolume(void); -void MUSIC_SetLoopFlag(int loopflag); -void MUSIC_Continue(void); -void MUSIC_Pause(void); -int MUSIC_StopSong(void); -int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn = nullptr); -void MUSIC_Update(void); +int MUSIC_Init(int SoundCard, int ForceEMIDI = -1); +int MUSIC_Shutdown(void); +void MUSIC_SetVolume(int volume); +int MUSIC_GetVolume(void); +void MUSIC_SetLoopFlag(int loopflag); +void MUSIC_Continue(void); +void MUSIC_Pause(void); +int MUSIC_StopSong(void); +int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn = nullptr); +void MUSIC_Update(void); #endif diff --git a/source/audiolib/include/sndcards.h b/source/audiolib/include/sndcards.h index 42310d155..bc6acffd7 100644 --- a/source/audiolib/include/sndcards.h +++ b/source/audiolib/include/sndcards.h @@ -36,8 +36,8 @@ typedef enum ASS_NoSound, ASS_SDL, ASS_DirectSound, - ASS_WinMM, ASS_OPL3, + ASS_WinMM, ASS_NumSoundCards, ASS_AutoDetect = -2 } soundcardnames; diff --git a/source/audiolib/src/_midi.h b/source/audiolib/src/_midi.h index 56a0f8793..160bdd812 100644 --- a/source/audiolib/src/_midi.h +++ b/source/audiolib/src/_midi.h @@ -25,11 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define ___MIDI_H #include "compat.h" -#ifdef OPL_MIDI_HEADER -namespace OPLMusic { -#endif -#define RELATIVE_BEAT( measure, beat, tick ) \ - ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) ) +#define RELATIVE_BEAT(measure, beat, tick) ((tick) + ((beat) << 9) + ((measure) << 16)) //Bobby Prince thinks this may be 100 //#define GENMIDI_DefaultVolume 100 @@ -105,7 +101,7 @@ namespace OPLMusic { #define EMIDI_GeneralMIDI 0 #define EMIDI_SoundBlaster 4 -#define EMIDI_Adlib 7 +#define EMIDI_AdLib 7 #define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type))) #define EMIDI_NUM_CONTEXTS 7 @@ -145,19 +141,16 @@ typedef struct char EMIDI_VolumeChange; } track; -static int _MIDI_ReadNumber(void *from, size_t size); -static int _MIDI_ReadDelta(track *ptr); +static int _MIDI_ReadNumber(void *from, size_t size); +static int _MIDI_ReadDelta(track *ptr); static void _MIDI_ResetTracks(void); static void _MIDI_AdvanceTick(void); static void _MIDI_MetaEvent(track *Track); static void _MIDI_SysEx(track *Track); -static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2); -static int _MIDI_SendControlChange(int channel, int c1, int c2); +static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2); +static int _MIDI_SendControlChange(int channel, int c1, int c2); static void _MIDI_SetChannelVolume(int channel, int volume); static void _MIDI_SendChannelVolumes(void); static void _MIDI_InitEMIDI(void); -#ifdef OPL_MIDI_HEADER -} -#endif #endif diff --git a/source/audiolib/src/driver_adlib.cpp b/source/audiolib/src/driver_adlib.cpp index 13268bc63..542c6e3d2 100644 --- a/source/audiolib/src/driver_adlib.cpp +++ b/source/audiolib/src/driver_adlib.cpp @@ -1,103 +1,973 @@ -/** - * Adlib MIDI output - */ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: AL_MIDI.C + + author: James R. Dose + date: April 1, 1994 + + Low level routines to support General MIDI music on AdLib compatible + cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ #include "driver_adlib.h" -#include "al_midi.h" -#include "compat.h" -#include "midifuncs.h" -#include "midi.h" +#include "_al_midi.h" #include "_multivc.h" +#include "compat.h" +#include "midi.h" +#include "midifuncs.h" +#include "opl3.h" -enum { - AdlibErr_Warning = -2, - AdlibErr_Error = -1, - AdlibErr_Ok = 0, - AdlibErr_Uninitialised, +enum +{ + AdLibErr_Warning = -2, + AdLibErr_Error = -1, + AdLibErr_Ok = 0, }; -static int ErrorCode = AdlibErr_Ok; +static int ErrorCode; -int AdlibDrv_GetError(void) -{ - return ErrorCode; -} +int AdLibDrv_GetError(void) { return ErrorCode; } -const char *AdlibDrv_ErrorString( int ErrorNumber ) +const char *AdLibDrv_ErrorString( int ErrorNumber ) { const char *ErrorString; switch( ErrorNumber ) { - case AdlibErr_Warning : - case AdlibErr_Error : - ErrorString = AdlibDrv_ErrorString( ErrorCode ); + case AdLibErr_Warning : + case AdLibErr_Error : + ErrorString = AdLibDrv_ErrorString( ErrorCode ); break; - case AdlibErr_Ok : - ErrorString = "Adlib ok."; + case AdLibErr_Ok : + ErrorString = "AdLib ok."; break; - case AdlibErr_Uninitialised: - ErrorString = "Adlib uninitialised."; - break; - default: - ErrorString = "Unknown Adlib error."; + ErrorString = "Unknown AdLib error."; break; } return ErrorString; } -int AdlibDrv_MIDI_Init(midifuncs *funcs) +int AdLibDrv_MIDI_Init(midifuncs *funcs) { - AdlibDrv_MIDI_Shutdown(); + AdLibDrv_MIDI_Shutdown(); Bmemset(funcs, 0, sizeof(midifuncs)); - funcs->NoteOff = OPLMusic::AL_NoteOff; - funcs->NoteOn = OPLMusic::AL_NoteOn; - funcs->PolyAftertouch = NULL; - funcs->ControlChange = OPLMusic::AL_ControlChange; - funcs->ProgramChange = OPLMusic::AL_ProgramChange; - funcs->ChannelAftertouch = NULL; - funcs->PitchBend = OPLMusic::AL_SetPitchBend; + funcs->NoteOff = AL_NoteOff; + funcs->NoteOn = AL_NoteOn; + funcs->PolyAftertouch = nullptr; + funcs->ControlChange = AL_ControlChange; + funcs->ProgramChange = AL_ProgramChange; + funcs->ChannelAftertouch = nullptr; + funcs->PitchBend = AL_SetPitchBend; - return AdlibErr_Ok; + return AdLibErr_Ok; } -void AdlibDrv_MIDI_Shutdown(void) -{ - AdlibDrv_MIDI_HaltPlayback(); -} +void AdLibDrv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); } +void AdLibDrv_MIDI_Shutdown(void) { AdLibDrv_MIDI_HaltPlayback(); } -int AdlibDrv_MIDI_StartPlayback(void (*service)(void)) +int AdLibDrv_MIDI_StartPlayback(void (*service)(void)) { - AdlibDrv_MIDI_HaltPlayback(); + AdLibDrv_MIDI_HaltPlayback(); - OPLMusic::AL_Init(MV_MixRate); + AL_Init(MV_MixRate); MV_HookMusicRoutine(service); return MIDI_Ok; } -void AdlibDrv_MIDI_HaltPlayback(void) +void AdLibDrv_MIDI_SetTempo(int tempo, int division) { - MV_UnhookMusicRoutine(); -} - -void AdlibDrv_MIDI_SetTempo(int tempo, int division) -{ - MV_MIDIRenderTempo = (tempo * division)/60; + MV_MIDIRenderTempo = tempo * division / 60; MV_MIDIRenderTimer = 0; } -void AdlibDrv_MIDI_Lock(void) +static opl3_chip chip; +opl3_chip *AL_GetChip() { return &chip; } + +static unsigned int OctavePitch[MAX_OCTAVE + 1] = { + OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3, OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7, +}; + +static unsigned int NoteMod12[MAX_NOTE + 1]; +static unsigned int NoteDiv12[MAX_NOTE + 1]; + +// Pitch table + +//static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] = +// { +// { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B }, +// }; + +static unsigned int 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 }, + { 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a }, + { 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b }, + { 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c }, + { 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e }, + { 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f }, + { 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 }, + { 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 }, + { 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 }, + { 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 }, + { 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 }, + { 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 }, + { 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 }, + { 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 }, + { 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 }, + { 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b }, + { 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c }, + { 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d }, + { 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e }, + { 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f }, + { 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 }, + { 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 }, + { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 }, + { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 }, + { 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 }, + { 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 }, + { 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 }, + { 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 }, + { 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab }, + { 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac } +}; + +// Slot numbers as a function of the voice and the operator. +// ( melodic only) + +static int slotVoice[NUMADLIBVOICES][2] = { + { 0, 3 }, // voice 0 + { 1, 4 }, // 1 + { 2, 5 }, // 2 + { 6, 9 }, // 3 + { 7, 10 }, // 4 + { 8, 11 }, // 5 + { 12, 15 }, // 6 + { 13, 16 }, // 7 + { 14, 17 }, // 8 +}; + +static int VoiceLevel[AL_NumChipSlots][2]; +static int VoiceKsl[AL_NumChipSlots][2]; + +// This table gives the offset of each slot within the chip. +// offset = fn( slot) + +static int8_t 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]; + +static AdLibVoice Voice[NUMADLIBVOICES * 2]; +static AdLibVoiceList Voice_Pool; + +static AdLibChannel Channel[NUMADLIBCHANNELS]; + +static int AL_LeftPort = ADLIB_PORT; +static int AL_RightPort = ADLIB_PORT; +static int AL_Stereo; +static int AL_SendStereo; +static int AL_OPL3; +static int AL_MaxMidiChannel = 16; + +#define OFFSET(structure, offset) (*((char **)&(structure)[offset])) + +#define LL_AddToTail(type, listhead, node) \ + LL_AddNode((char *)(node), (char **)&((listhead)->end), (char **)&((listhead)->start), (intptr_t) & ((type *)0)->prev, \ + (intptr_t) & ((type *)0)->next) + +#define LL_Remove(type, listhead, node) \ + LL_RemoveNode((char *)(node), (char **)&((listhead)->start), (char **)&((listhead)->end), (intptr_t) & ((type *)0)->next, \ + (intptr_t) & ((type *)0)->prev) + +static void LL_RemoveNode(char *item, char **head, char **tail, intptr_t next, intptr_t prev) { + if (OFFSET(item, prev) == nullptr) + *head = OFFSET(item, next); + else + OFFSET(OFFSET(item, prev), next) = OFFSET(item, next); + + if (OFFSET(item, next) == nullptr) + *tail = OFFSET(item, prev); + else + OFFSET(OFFSET(item, next), prev) = OFFSET(item, prev); + + OFFSET(item, next) = nullptr; + OFFSET(item, prev) = nullptr; } -void AdlibDrv_MIDI_Unlock(void) +static void LL_AddNode(char *item, char **head, char **tail, intptr_t next, intptr_t prev) { + OFFSET(item, prev) = nullptr; + OFFSET(item, next) = *head; + + if (*head) + OFFSET(*head, prev) = item; + else + *tail = item; + + *head = item; } + +static void AL_SendOutputToPort(int port, int reg, int data) { OPL3_WriteRegBuffered(&chip, (Bit16u)(reg + ((port & 2) << 7)), (Bit8u)data); } + + +static void AL_SendOutput(int voice, int reg, int data) +{ + if (AL_SendStereo) + { + AL_SendOutputToPort(AL_LeftPort, reg, data); + AL_SendOutputToPort(AL_RightPort, reg, data); + } + else + { + int port = (voice == 0) ? AL_RightPort : AL_LeftPort; + AL_SendOutputToPort(port, reg, data); + } +} + + +static void AL_SetVoiceTimbre(int voice) +{ + int channel = Voice[voice].channel; + int patch = (channel == 9) ? Voice[voice].key + 128 : Channel[channel].Timbre; + + if (Voice[voice].timbre == patch) + return; + + Voice[voice].timbre = patch; + + auto timbre = &ADLIB_TimbreBank[patch]; + + int port = Voice[voice].port; + int voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : 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; + + AL_SendOutput(port, 0xA0 + voc, 0); + AL_SendOutput(port, 0xB0 + voc, 0); + + // Let voice clear the release + AL_SendOutput(port, 0x80 + 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, 0x40 + off, timbre->Level[0]); + slot = slotVoice[voc][1]; + + if (AL_SendStereo) + { + AL_SendOutputToPort(AL_LeftPort, 0xC0 + voice, (timbre->Feedback & 0x0f) | 0x20); + AL_SendOutputToPort(AL_RightPort, 0xC0 + voice, (timbre->Feedback & 0x0f) | 0x10); + } + else + { + if (AL_OPL3) + AL_SendOutput(port, 0xC0 + voc, (timbre->Feedback & 0x0f) | 0x30); + else + AL_SendOutputToPort(ADLIB_PORT, 0xC0 + voice, timbre->Feedback); + } + + off = offsetSlot[slot]; + + VoiceLevel[slot][port] = 63 - (timbre->Level[1] & 0x3f); + VoiceKsl[slot][port] = timbre->Level[1] & 0xc0; + + AL_SendOutput(port, 0x40 + off, 63); + + // Let voice clear the release + AL_SendOutput(port, 0x80 + 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]); +} + + +static void AL_SetVoiceVolume(int voice) +{ + int channel = Voice[voice].channel; + + auto timbre = &ADLIB_TimbreBank[Voice[voice].timbre]; + + int velocity = Voice[voice].velocity + timbre->Velocity; + velocity = std::min(velocity, MAX_VELOCITY); + + int voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice; + int slot = slotVoice[voc][1]; + int port = Voice[voice].port; + + // amplitude + uint32_t t1 = (unsigned int)VoiceLevel[slot][port]; + t1 *= (velocity + 0x80); + t1 = (Channel[channel].Volume * t1) >> 15; + + if (!AL_SendStereo) + { + uint32_t volume = t1 ^ 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutput(port, 0x40 + offsetSlot[slot], volume); + + // Check if this timbre is Additive + if (timbre->Feedback & 0x01) + { + slot = slotVoice[voc][0]; + + // amplitude + uint32_t t2 = (unsigned int)VoiceLevel[slot][port]; + t2 *= (velocity + 0x80); + t2 = (Channel[channel].Volume * t1) >> 15; + + volume = t2 ^ 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutput(port, 0x40 + offsetSlot[slot], volume); + } + + return; + } + + // Set left channel volume + uint32_t volume = t1; + if (Channel[channel].Pan < 64) + { + volume *= Channel[channel].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutputToPort(AL_LeftPort, 0x40 + offsetSlot[slot], volume); + + // Set right channel volume + volume = t1; + if (Channel[channel].Pan > 64) + { + volume *= 127 - Channel[channel].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutputToPort(AL_RightPort, 0x40 + offsetSlot[slot], volume); + + // Check if this timbre is Additive + if (timbre->Feedback & 0x01) + { + // amplitude + uint32_t t2 = (unsigned int)VoiceLevel[slot][port]; + t2 *= (velocity + 0x80); + t2 = (Channel[channel].Volume * t1) >> 15; + + slot = slotVoice[voc][0]; + + // Set left channel volume + volume = t2; + if (Channel[channel].Pan < 64) + { + volume *= Channel[channel].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutputToPort(AL_LeftPort, 0x40 + offsetSlot[slot], volume); + + // Set right channel volume + volume = t2; + if (Channel[channel].Pan > 64) + { + volume *= 127 - Channel[channel].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= (unsigned int)VoiceKsl[slot][port]; + + AL_SendOutputToPort(AL_RightPort, 0x40 + offsetSlot[slot], volume); + } +} + + +static int AL_AllocVoice(void) +{ + if (Voice_Pool.start) + { + int voice = Voice_Pool.start->num; + LL_Remove(AdLibVoice, &Voice_Pool, &Voice[voice]); + return voice; + } + + return AL_VoiceNotFound; +} + + +static int AL_GetVoice(int channel, int key) +{ + auto voice = Channel[channel].Voices.start; + + while (voice != nullptr) + { + if (voice->key == (unsigned int)key) + return voice->num; + voice = voice->next; + } + + return AL_VoiceNotFound; +} + + +static void AL_SetVoicePitch(int voice) +{ + int port = Voice[voice].port; + int voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice; + int channel = Voice[voice].channel; + + int patch, note; + + if (channel == 9) + { + patch = Voice[voice].key + 128; + note = ADLIB_TimbreBank[patch].Transpose; + } + else + { + patch = Channel[channel].Timbre; + note = Voice[voice].key + ADLIB_TimbreBank[patch].Transpose; + } + + note += Channel[channel].KeyOffset - 12; + note = clamp(note, 0, MAX_NOTE); + + int detune = Channel[channel].KeyDetune; + + int ScaleNote = NoteMod12[note]; + int Octave = NoteDiv12[note]; + + int pitch = OctavePitch[Octave] | NotePitch[detune][ScaleNote]; + + Voice[voice].pitchleft = pitch; + + pitch |= Voice[voice].status; + + if (!AL_SendStereo) + { + AL_SendOutput(port, 0xA0 + voc, pitch); + AL_SendOutput(port, 0xB0 + voc, pitch >> 8); + } + else + { + AL_SendOutputToPort(AL_LeftPort, 0xA0 + voice, pitch); + AL_SendOutputToPort(AL_LeftPort, 0xB0 + voice, pitch >> 8); + + if (channel != 9) + detune += STEREO_DETUNE; + + if (detune > FINETUNE_MAX) + { + detune -= FINETUNE_RANGE; + + if (note < MAX_NOTE) + { + note++; + ScaleNote = NoteMod12[note]; + Octave = NoteDiv12[note]; + } + } + + pitch = OctavePitch[Octave] | NotePitch[detune][ScaleNote]; + + Voice[voice].pitchright = pitch; + + pitch |= Voice[voice].status; + + AL_SendOutputToPort(AL_RightPort, 0xA0 + voice, pitch); + AL_SendOutputToPort(AL_RightPort, 0xB0 + voice, pitch >> 8); + } +} + + +static void AL_SetChannelVolume(int channel, int volume) +{ + volume = max(0, volume); + volume = min(volume, AL_MaxVolume); + + Channel[channel].Volume = volume; + + auto voice = Channel[channel].Voices.start; + + while (voice != nullptr) + { + AL_SetVoiceVolume(voice->num); + voice = voice->next; + } +} + + +static void AL_SetChannelPan(int channel, int pan) +{ + // Don't pan drum sounds + if (channel != 9) + Channel[channel].Pan = pan; +} + + +static void AL_SetChannelDetune(int channel, int detune) { Channel[channel].Detune = detune; } + + +static void AL_ResetVoices(void) +{ + Voice_Pool.start = nullptr; + Voice_Pool.end = nullptr; + + int numvoices = NUMADLIBVOICES; + + if ((AL_OPL3) && (!AL_Stereo)) + numvoices = NUMADLIBVOICES * 2; + + for (int index = 0; index < numvoices; index++) + { + if (VoiceReserved[index] == FALSE) + { + Voice[index].num = index; + Voice[index].key = 0; + Voice[index].velocity = 0; + Voice[index].channel = -1; + Voice[index].timbre = -1; + Voice[index].port = (index < NUMADLIBVOICES) ? 0 : 1; + Voice[index].status = NOTE_OFF; + LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[index]); + } + } + + for (int index = 0; index < NUMADLIBCHANNELS; index++) + { + Channel[index].Voices.start = nullptr; + Channel[index].Voices.end = nullptr; + Channel[index].Timbre = 0; + Channel[index].Pitchbend = 0; + Channel[index].KeyOffset = 0; + Channel[index].KeyDetune = 0; + Channel[index].Volume = AL_DefaultChannelVolume; + Channel[index].Pan = 64; + Channel[index].RPN = 0; + Channel[index].PitchBendRange = AL_DefaultPitchBendRange; + Channel[index].PitchBendSemiTones = AL_DefaultPitchBendRange / 100; + Channel[index].PitchBendHundreds = AL_DefaultPitchBendRange % 100; + } +} + + +static void AL_CalcPitchInfo(void) +{ + // int finetune; + // double detune; + + for (int note = 0; note <= MAX_NOTE; note++) + { + NoteMod12[note] = note % 12; + NoteDiv12[note] = note / 12; + } + + // for( finetune = 1; finetune <= FINETUNE_MAX; finetune++ ) + // { + // detune = pow( 2, ( double )finetune / ( 12.0 * FINETUNE_RANGE ) ); + // for( note = 0; note < 12; note++ ) + // { + // NotePitch[ finetune ][ note ] = ( ( double )NotePitch[ 0 ][ note ] * detune ); + // } + // } +} + + +static void AL_FlushCard(int port) +{ + for (int i = 0; i < NUMADLIBVOICES; i++) + { + if (VoiceReserved[i] == FALSE) + { + unsigned slot1 = offsetSlot[slotVoice[i][0]]; + unsigned slot2 = offsetSlot[slotVoice[i][1]]; + + AL_SendOutputToPort(port, 0xA0 + i, 0); + AL_SendOutputToPort(port, 0xB0 + i, 0); + + AL_SendOutputToPort(port, 0xE0 + slot1, 0); + AL_SendOutputToPort(port, 0xE0 + 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); + + // Maximum attenuation + AL_SendOutputToPort(port, 0x40 + slot1, 0xff); + AL_SendOutputToPort(port, 0x40 + slot2, 0xff); + } + } +} + + +static void AL_StereoOn(void) +{ + if ((AL_Stereo) && (!AL_SendStereo)) + { + AL_SendStereo = TRUE; + if (AL_OPL3) + { + // Set card to OPL3 operation + AL_SendOutputToPort(AL_RightPort, 0x5, 1); + } + } + else if (AL_OPL3) + { + // Set card to OPL3 operation + AL_SendOutputToPort(AL_RightPort, 0x5, 1); + } +} + + +static void AL_StereoOff(void) +{ + if ((AL_Stereo) && (AL_SendStereo)) + { + AL_SendStereo = FALSE; + if (AL_OPL3) + { + // Set card back to OPL2 operation + AL_SendOutputToPort(AL_RightPort, 0x5, 0); + } + } + else if (AL_OPL3) + { + // Set card back to OPL2 operation + AL_SendOutputToPort(AL_RightPort, 0x5, 0); + } +} + + +static void AL_Reset(void) +{ + AL_SendOutputToPort(ADLIB_PORT, 1, 0x20); + AL_SendOutputToPort(ADLIB_PORT, 0x08, 0); + + // Set the values: AM Depth, VIB depth & Rhythm + AL_SendOutputToPort(ADLIB_PORT, 0xBD, 0); + + AL_StereoOn(); + + if ((AL_SendStereo) || (AL_OPL3)) + { + AL_FlushCard(AL_LeftPort); + AL_FlushCard(AL_RightPort); + } + else + AL_FlushCard(ADLIB_PORT); +} + + +static int AL_ReserveVoice(int voice) +{ + if ((voice < 0) || (voice >= NUMADLIBVOICES)) + return AdLibErr_Error; + + if (VoiceReserved[voice]) + return AdLibErr_Warning; + + if (Voice[voice].status == NOTE_ON) + AL_NoteOff(Voice[voice].channel, Voice[voice].key, 0); + + VoiceReserved[voice] = TRUE; + LL_Remove(AdLibVoice, &Voice_Pool, &Voice[voice]); + + return AdLibErr_Ok; +} + + +static int AL_ReleaseVoice(int voice) +{ + if ((voice < 0) || (voice >= NUMADLIBVOICES)) + return AdLibErr_Error; + + if (!VoiceReserved[voice]) + return AdLibErr_Warning; + + VoiceReserved[voice] = FALSE; + LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[voice]); + + return AdLibErr_Ok; +} + + +static void AL_NoteOff(int channel, int key, int velocity) +{ + UNREFERENCED_PARAMETER(velocity); + + // We only play channels 1 through 10 + if (channel > AL_MaxMidiChannel) + return; + + int 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; + + if (AL_SendStereo) + { + AL_SendOutputToPort(AL_LeftPort, 0xB0 + voice, hibyte(Voice[voice].pitchleft)); + AL_SendOutputToPort(AL_RightPort, 0xB0 + voice, hibyte(Voice[voice].pitchright)); + } + else + AL_SendOutput(port, 0xB0 + voc, hibyte(Voice[voice].pitchleft)); + + LL_Remove(AdLibVoice, &Channel[channel].Voices, &Voice[voice]); + LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[voice]); +} + + +static void AL_NoteOn(int channel, int key, int velocity) +{ + // We only play channels 1 through 10 + if (channel > AL_MaxMidiChannel) + return; + + if (velocity == 0) + { + AL_NoteOff(channel, key, velocity); + return; + } + + int voice = AL_AllocVoice(); + + if (voice == AL_VoiceNotFound) + { + if (Channel[9].Voices.start) + { + AL_NoteOff(9, Channel[9].Voices.start->key, 0); + voice = AL_AllocVoice(); + } + if (voice == AL_VoiceNotFound) + { + return; + } + } + + Voice[voice].key = key; + Voice[voice].channel = channel; + Voice[voice].velocity = velocity; + Voice[voice].status = NOTE_ON; + + LL_AddToTail(AdLibVoice, &Channel[channel].Voices, &Voice[voice]); + + AL_SetVoiceTimbre(voice); + AL_SetVoiceVolume(voice); + AL_SetVoicePitch(voice); +} + + +static void AL_AllNotesOff(int channel) +{ + while (Channel[channel].Voices.start != nullptr) + { + AL_NoteOff(channel, Channel[channel].Voices.start->key, 0); + } +} + + +static void AL_ControlChange(int channel, int type, int data) +{ + // We only play channels 1 through 10 + if (channel > AL_MaxMidiChannel) + return; + + switch (type) + { + case MIDI_VOLUME: + AL_SetChannelVolume(channel, data); + break; + + case MIDI_PAN: + AL_SetChannelPan(channel, data); + break; + + case MIDI_DETUNE: + AL_SetChannelDetune(channel, data); + break; + + case MIDI_ALL_NOTES_OFF: + AL_AllNotesOff(channel); + break; + + case MIDI_RESET_ALL_CONTROLLERS: + AL_ResetVoices(); + AL_SetChannelVolume(channel, AL_DefaultChannelVolume); + AL_SetChannelPan(channel, 64); + AL_SetChannelDetune(channel, 0); + break; + + case MIDI_RPN_MSB: + Channel[channel].RPN &= 0x00FF; + Channel[channel].RPN |= (data & 0xFF) << 8; + break; + + case MIDI_RPN_LSB: + Channel[channel].RPN &= 0xFF00; + Channel[channel].RPN |= data & 0xFF; + break; + + case MIDI_DATAENTRY_MSB: + if (Channel[channel].RPN == MIDI_PITCHBEND_RPN) + { + Channel[channel].PitchBendSemiTones = data; + Channel[channel].PitchBendRange = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds; + } + break; + + case MIDI_DATAENTRY_LSB: + if (Channel[channel].RPN == MIDI_PITCHBEND_RPN) + { + Channel[channel].PitchBendHundreds = data; + Channel[channel].PitchBendRange = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds; + } + break; + } +} + + +static void AL_ProgramChange(int channel, int patch) +{ + // We only play channels 1 through 10 + if (channel > AL_MaxMidiChannel) + return; + + Channel[channel].Timbre = patch; +} + + +static void AL_SetPitchBend(int channel, int lsb, int msb) +{ + int pitchbend; + int TotalBend; + AdLibVoice *voice; + + // We only play channels 1 through 10 + if (channel > AL_MaxMidiChannel) + return; + + pitchbend = lsb + (msb << 8); + + Channel[channel].Pitchbend = pitchbend; + + TotalBend = pitchbend * Channel[channel].PitchBendRange; + TotalBend /= (PITCHBEND_CENTER / FINETUNE_RANGE); + + Channel[channel].KeyOffset = (int)(TotalBend / FINETUNE_RANGE); + Channel[channel].KeyOffset -= Channel[channel].PitchBendSemiTones; + + Channel[channel].KeyDetune = (unsigned int)(TotalBend % FINETUNE_RANGE); + + voice = Channel[channel].Voices.start; + while (voice != nullptr) + { + AL_SetVoicePitch(voice->num); + voice = voice->next; + } +} + + +static void AL_Shutdown(void) +{ + AL_StereoOff(); + + AL_OPL3 = FALSE; + AL_ResetVoices(); + AL_Reset(); +} + + +static void AL_SetMaxMidiChannel(int channel) { AL_MaxMidiChannel = channel - 1; } + +static int AL_Init(int rate) +{ + OPL3_Reset(&chip, rate); + + AL_Stereo = FALSE; + // AL_OPL3 = FALSE; + // AL_LeftPort = ADLIB_PORT; + // AL_RightPort = ADLIB_PORT; + + AL_OPL3 = TRUE; + AL_LeftPort = ADLIB_PORT; + AL_RightPort = ADLIB_PORT + 2; + + AL_CalcPitchInfo(); + AL_Reset(); + AL_ResetVoices(); + + return AdLibErr_Ok; +} + + +void AL_RegisterTimbreBank(uint8_t *timbres) +{ + for (int i = 0; i < 256; i++) + { + ADLIB_TimbreBank[i].SAVEK[0] = *(timbres++); + ADLIB_TimbreBank[i].SAVEK[1] = *(timbres++); + ADLIB_TimbreBank[i].Level[0] = *(timbres++); + ADLIB_TimbreBank[i].Level[1] = *(timbres++); + ADLIB_TimbreBank[i].Env1[0] = *(timbres++); + ADLIB_TimbreBank[i].Env1[1] = *(timbres++); + ADLIB_TimbreBank[i].Env2[0] = *(timbres++); + ADLIB_TimbreBank[i].Env2[1] = *(timbres++); + ADLIB_TimbreBank[i].Wave[0] = *(timbres++); + ADLIB_TimbreBank[i].Wave[1] = *(timbres++); + ADLIB_TimbreBank[i].Feedback = *(timbres++); + ADLIB_TimbreBank[i].Transpose = *(int8_t *)(timbres++); + ADLIB_TimbreBank[i].Velocity = *(int8_t *)(timbres++); + } +} diff --git a/source/audiolib/src/driver_adlib.h b/source/audiolib/src/driver_adlib.h index 48ab496b2..362b0210c 100644 --- a/source/audiolib/src/driver_adlib.h +++ b/source/audiolib/src/driver_adlib.h @@ -18,15 +18,16 @@ */ +#include "al_midi.h" #include "midifuncs.h" +#include "opl3.h" -int AdlibDrv_GetError(void); -const char *AdlibDrv_ErrorString( int ErrorNumber ); +int AdLibDrv_GetError(void); +const char *AdLibDrv_ErrorString(int ErrorNumber); + +int AdLibDrv_MIDI_Init(midifuncs *); +void AdLibDrv_MIDI_Shutdown(void); +int AdLibDrv_MIDI_StartPlayback(void (*service)(void)); +void AdLibDrv_MIDI_HaltPlayback(void); +void AdLibDrv_MIDI_SetTempo(int tempo, int division); -int AdlibDrv_MIDI_Init(midifuncs *); -void AdlibDrv_MIDI_Shutdown(void); -int AdlibDrv_MIDI_StartPlayback(void (*service)(void)); -void AdlibDrv_MIDI_HaltPlayback(void); -void AdlibDrv_MIDI_SetTempo(int tempo, int division); -void AdlibDrv_MIDI_Lock(void); -void AdlibDrv_MIDI_Unlock(void); diff --git a/source/audiolib/src/driver_directsound.h b/source/audiolib/src/driver_directsound.h index 840914322..68874707d 100644 --- a/source/audiolib/src/driver_directsound.h +++ b/source/audiolib/src/driver_directsound.h @@ -18,7 +18,7 @@ */ -#include "inttypes.h" +#include enum { diff --git a/source/audiolib/src/driver_sdl.cpp b/source/audiolib/src/driver_sdl.cpp index f033c51f9..5f197bcd9 100644 --- a/source/audiolib/src/driver_sdl.cpp +++ b/source/audiolib/src/driver_sdl.cpp @@ -98,7 +98,7 @@ int SDLDrv_GetError(void) return ErrorCode; } -const char *SDLDrv_ErrorString( int ErrorNumber ) +const char *SDLDrv_ErrorString(int ErrorNumber) { const char *ErrorString; @@ -173,7 +173,7 @@ int SDLDrv_PCM_Init(int *mixrate, int *numchannels, void * initdata) #if (SDL_MAJOR_VERSION == 1) err = !SDL_OpenAudio(&spec, &actual); #else - audio_dev = err = SDL_OpenAudioDevice(NULL, 0, &spec, &actual, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); + audio_dev = err = SDL_OpenAudioDevice(nullptr, 0, &spec, &actual, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); #endif if (err == 0) { @@ -186,12 +186,25 @@ int SDLDrv_PCM_Init(int *mixrate, int *numchannels, void * initdata) SDL_AudioDriverName(drivername, sizeof(drivername)); MV_Printf("SDL %s driver\n", drivername); #else - char *drivername = Xstrdup(SDL_GetCurrentAudioDriver()); + auto drivername = Xstrdup(SDL_GetCurrentAudioDriver()); for (int i=0;drivername[i] != 0;++i) drivername[i] = toupperlookup[drivername[i]]; - MV_Printf("SDL %s driver on %s\n", drivername ? drivername : "(error)", SDL_GetAudioDeviceName(0, 0)); + auto devname = Xstrdup(SDL_GetAudioDeviceName(0, 0)); + auto pdevname = Bstrchr(devname, '('); + + if (pdevname) + { + auto rt = Bstrchr(pdevname++, ')'); + if (rt != nullptr) *rt = '\0'; + } + else + pdevname = devname; + + MV_Printf("SDL %s driver on %s\n", drivername, pdevname); + + Xfree(devname); Xfree(drivername); #endif diff --git a/source/audiolib/src/driver_winmm.cpp b/source/audiolib/src/driver_winmm.cpp index 06e7394c1..e32bdf31a 100644 --- a/source/audiolib/src/driver_winmm.cpp +++ b/source/audiolib/src/driver_winmm.cpp @@ -649,7 +649,7 @@ static DWORD WINAPI midiDataThread(LPVOID lpParameter) DWORD sequenceTime; DWORD sleepAmount = 100 / THREAD_QUEUE_INTERVAL; - MV_Printf("WinMM midiDataThread: started\n"); + // MV_Printf("WinMM midiDataThread: started\n"); midiThreadTimer = midi_get_tick(); midiLastEventTime = midiThreadTimer; @@ -669,7 +669,7 @@ static DWORD WINAPI midiDataThread(LPVOID lpParameter) do { waitret = WaitForSingleObject(midiThreadQuitEvent, sleepAmount); if (waitret == WAIT_OBJECT_0) { - MV_Printf("WinMM midiDataThread: exiting\n"); + // MV_Printf("WinMM midiDataThread: exiting\n"); break; } else if (waitret == WAIT_TIMEOUT) { // queue a tick @@ -712,7 +712,7 @@ int WinMMDrv_MIDI_StartPlayback(void (*service)(void)) midiThreadService = service; - midiThreadQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + midiThreadQuitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (!midiThreadQuitEvent) { ErrorCode = WinMMErr_MIDICreateEvent; return WinMMErr_Error; @@ -730,7 +730,7 @@ int WinMMDrv_MIDI_StartPlayback(void (*service)(void)) midiStreamRunning = TRUE; } - midiThread = CreateThread(NULL, 0, midiDataThread, 0, 0, 0); + midiThread = CreateThread(nullptr, 0, midiDataThread, 0, 0, 0); if (!midiThread) { WinMMDrv_MIDI_HaltPlayback(); ErrorCode = WinMMErr_MIDIPlayThread; @@ -748,7 +748,7 @@ void WinMMDrv_MIDI_HaltPlayback(void) SetEvent(midiThreadQuitEvent); WaitForSingleObject(midiThread, INFINITE); - MV_Printf("WinMM MIDI_HaltPlayback synched\n"); + // MV_Printf("WinMM MIDI_HaltPlayback synched\n"); CloseHandle(midiThread); } @@ -758,12 +758,12 @@ void WinMMDrv_MIDI_HaltPlayback(void) } if (midiStreamRunning) { - MV_Printf("stopping stream\n"); + // MV_Printf("stopping stream\n"); rv = midiStreamStop(midiStream); if (rv != MMSYSERR_NOERROR) { midi_error(rv, "WinMM MIDI_HaltPlayback midiStreamStop"); } - MV_Printf("stream stopped\n"); + // MV_Printf("stream stopped\n"); midiStreamRunning = FALSE; } diff --git a/source/audiolib/src/drivers.cpp b/source/audiolib/src/drivers.cpp index 7c81bc34c..1a49a6ad7 100644 --- a/source/audiolib/src/drivers.cpp +++ b/source/audiolib/src/drivers.cpp @@ -39,6 +39,7 @@ int ASS_PCMSoundDriver = ASS_AutoDetect; int ASS_MIDISoundDriver = ASS_AutoDetect; +int ASS_EMIDICard = -1; #define UNSUPPORTED_PCM 0,0,0,0,0,0 #define UNSUPPORTED_MIDI 0,0,0,0,0,0,0 @@ -68,7 +69,7 @@ static struct { // Everyone gets the "no sound" driver { - "No Sound", + "null sound device", NoSoundDrv_GetError, NoSoundDrv_ErrorString, NoSoundDrv_PCM_Init, @@ -103,9 +104,9 @@ static struct { #else UNSUPPORTED_COMPLETELY #endif - + // Windows DirectSound - #ifdef _WIN32 + #ifdef RENDERTYPEWIN { "DirectSound", DirectSoundDrv_GetError, @@ -122,6 +123,23 @@ static struct { UNSUPPORTED_COMPLETELY #endif + // OPL3 emulation + { + "Nuked OPL3 AdLib emulator", + AdLibDrv_GetError, + AdLibDrv_ErrorString, + + UNSUPPORTED_PCM, + + AdLibDrv_MIDI_Init, + AdLibDrv_MIDI_Shutdown, + AdLibDrv_MIDI_StartPlayback, + AdLibDrv_MIDI_HaltPlayback, + AdLibDrv_MIDI_SetTempo, + nullptr, + nullptr, + }, + // Windows MultiMedia system #ifdef _WIN32 { @@ -142,23 +160,6 @@ static struct { #else UNSUPPORTED_COMPLETELY #endif - - // OPL3 emulation - { - "Nuked OPL3", - AdlibDrv_GetError, - AdlibDrv_ErrorString, - - UNSUPPORTED_PCM, - - AdlibDrv_MIDI_Init, - AdlibDrv_MIDI_Shutdown, - AdlibDrv_MIDI_StartPlayback, - AdlibDrv_MIDI_HaltPlayback, - AdlibDrv_MIDI_SetTempo, - AdlibDrv_MIDI_Lock, - AdlibDrv_MIDI_Unlock, - }, }; @@ -223,7 +224,7 @@ int SoundDriver_MIDI_StartPlayback(void (*service)(void)) { return SoundDrivers void SoundDriver_MIDI_Shutdown(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_Shutdown(); } void SoundDriver_MIDI_HaltPlayback(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_HaltPlayback(); } void SoundDriver_MIDI_SetTempo(int tempo, int division) { SoundDrivers[ASS_MIDISoundDriver].MIDI_SetTempo(tempo, division); } -void SoundDriver_MIDI_Lock(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_Lock(); } -void SoundDriver_MIDI_Unlock(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_Unlock(); } +void SoundDriver_MIDI_Lock(void) { if (SoundDrivers[ASS_MIDISoundDriver].MIDI_Lock) SoundDrivers[ASS_MIDISoundDriver].MIDI_Lock(); } +void SoundDriver_MIDI_Unlock(void) { if (SoundDrivers[ASS_MIDISoundDriver].MIDI_Unlock) SoundDrivers[ASS_MIDISoundDriver].MIDI_Unlock(); } // vim:ts=4:sw=4:expandtab: diff --git a/source/audiolib/src/fx_man.cpp b/source/audiolib/src/fx_man.cpp index bc49e4763..245b66989 100644 --- a/source/audiolib/src/fx_man.cpp +++ b/source/audiolib/src/fx_man.cpp @@ -54,7 +54,7 @@ int FX_Init(int numvoices, int numchannels, unsigned mixrate, void *initdata) if (SoundCard == ASS_AutoDetect) { #if defined RENDERTYPESDL SoundCard = ASS_SDL; -#elif defined _WIN32 +#elif defined RENDERTYPEWIN SoundCard = ASS_DirectSound; #else SoundCard = ASS_NoSound; diff --git a/source/audiolib/src/gmtimbre.cpp b/source/audiolib/src/gmtimbre.cpp index 6c751a82d..809d65abc 100644 --- a/source/audiolib/src/gmtimbre.cpp +++ b/source/audiolib/src/gmtimbre.cpp @@ -19,22 +19,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#include "_al_midi.h" -namespace OPLMusic { - -typedef struct - { - uint8_t SAVEK[ 2 ]; - uint8_t Level[ 2 ]; - uint8_t Env1[ 2 ]; - uint8_t Env2[ 2 ]; - uint8_t Wave[ 2 ]; - uint8_t Feedback; - int8_t Transpose; - int8_t Velocity; - } TIMBRE; - -TIMBRE ADLIB_TimbreBank[ 256 ] = +AdLibTimbre ADLIB_TimbreBank[256] = { { { 33, 33 }, { 143, 6 }, { 242, 242 }, { 69, 118 }, { 0, 0 }, 8, 0, 0 }, { { 49, 33 }, { 75, 0 }, { 242, 242 }, { 84, 86 }, { 0, 0 }, 8, 0, 0 }, @@ -293,5 +280,3 @@ TIMBRE ADLIB_TimbreBank[ 256 ] = { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 }, { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 } }; - -} diff --git a/source/audiolib/src/midi.cpp b/source/audiolib/src/midi.cpp index de995c22c..9d89f72c0 100644 --- a/source/audiolib/src/midi.cpp +++ b/source/audiolib/src/midi.cpp @@ -38,12 +38,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "_midi.h" #include "_multivc.h" -#include "al_midi.h" #include "compat.h" #include "multivoc.h" #include "music.h" #include "pragmas.h" #include "sndcards.h" +#include "driver_adlib.h" extern int MV_MixRate; extern int ASS_MIDISoundDriver; @@ -86,8 +86,6 @@ static midifuncs *_MIDI_Funcs; static int _MIDI_Reset; -static int MIDI_Tempo = 120; - int MV_MIDIRenderTempo = -1; int MV_MIDIRenderTimer; @@ -270,7 +268,7 @@ static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, case EMIDI_CONTEXT_END : if ((Track->currentcontext == _MIDI_Context) || (_MIDI_Context < 0) || - (Track->context[_MIDI_Context].pos == NULL)) + (Track->context[_MIDI_Context].pos == nullptr)) break; Track->currentcontext = _MIDI_Context; @@ -333,7 +331,7 @@ static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, case EMIDI_LOOP_END : case EMIDI_SONG_LOOP_END : - if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[0].loopstart == NULL) || (Track->context[0].loopcount == 0)) + if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[0].loopstart == nullptr) || (Track->context[0].loopcount == 0)) break; if (c1 == EMIDI_SONG_LOOP_END) @@ -507,9 +505,30 @@ static void _MIDI_ServiceRoutine(void) _MIDI_GlobalPositionInTicks++; } +static void _MIDI_ServiceMultivoc(void) +{ + int16_t * buffer16 = (int16_t *)MV_MusicBuffer; + int const samples = MV_BufferSize >> 2; + + for (int i = 0; i < samples; i++) + { + Bit16s buf[2]; + while (MV_MIDIRenderTimer >= MV_MixRate) + { + if (MV_MIDIRenderTempo >= 0) + _MIDI_ServiceRoutine(); + MV_MIDIRenderTimer -= MV_MixRate; + } + if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo; + OPL3_GenerateResampled(AL_GetChip(), buf); + *buffer16++ = clamp(buf[0]<<1, INT16_MIN, INT16_MAX); + *buffer16++ = clamp(buf[1]<<1, INT16_MIN, INT16_MAX); + } +} + static int _MIDI_SendControlChange(int channel, int c1, int c2) { - if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL) + if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ControlChange == nullptr) return MIDI_Error; _MIDI_Funcs->ControlChange(channel, c1, c2); @@ -517,6 +536,16 @@ static int _MIDI_SendControlChange(int channel, int c1, int c2) return MIDI_Ok; } +static int _MIDI_SendProgramChange(int channel, int c1) +{ + if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ProgramChange == nullptr) + return MIDI_Error; + + _MIDI_Funcs->ProgramChange(channel, c1); + + return MIDI_Ok; +} + int MIDI_AllNotesOff(void) { SoundDriver_MIDI_Lock(); @@ -536,9 +565,9 @@ int MIDI_AllNotesOff(void) static void _MIDI_SetChannelVolume(int channel, int volume) { - _MIDI_ChannelVolume[ channel ] = volume; + _MIDI_ChannelVolume[channel] = volume; - if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL) + if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ControlChange == nullptr) return; volume *= _MIDI_TotalVolume; @@ -566,7 +595,13 @@ int MIDI_Reset(void) _MIDI_SendControlChange(channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB); _MIDI_SendControlChange(channel, MIDI_DATAENTRY_MSB, 2); /* Pitch Bend Sensitivity MSB */ _MIDI_SendControlChange(channel, MIDI_DATAENTRY_LSB, 0); /* Pitch Bend Sensitivity LSB */ - _MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume; + _MIDI_ChannelVolume[channel] = GENMIDI_DefaultVolume; + _MIDI_SendControlChange(channel, MIDI_PAN, 64); // begin TURRICAN's recommendation + _MIDI_SendControlChange(channel, MIDI_REVERB, 40); + _MIDI_SendControlChange(channel, MIDI_CHORUS, 0); + _MIDI_SendControlChange(channel, MIDI_BANK_SELECT_MSB, 0); + _MIDI_SendControlChange(channel, MIDI_BANK_SELECT_LSB, 0); + _MIDI_SendProgramChange(channel, 0); // end TURRICAN's recommendation } _MIDI_SendChannelVolumes(); @@ -581,7 +616,7 @@ int MIDI_Reset(void) int MIDI_SetVolume(int volume) { - if (_MIDI_Funcs == NULL) + if (_MIDI_Funcs == nullptr) return MIDI_NullMidiModule; volume = min(MIDI_MaxVolume, volume); @@ -604,7 +639,7 @@ int MIDI_SetVolume(int volume) int MIDI_GetVolume(void) { - if (_MIDI_Funcs == NULL) + if (_MIDI_Funcs == nullptr) return MIDI_NullMidiModule; SoundDriver_MIDI_Lock(); @@ -668,7 +703,7 @@ int MIDI_PlaySong(char *song, int loopflag) track *CurrentTrack; char *ptr; - if (_MIDI_Funcs == NULL) + if (_MIDI_Funcs == nullptr) return MIDI_NullMidiModule; if (B_UNBUF32(song) != MIDI_HEADER_SIGNATURE) @@ -723,7 +758,6 @@ int MIDI_PlaySong(char *song, int loopflag) if (_MIDI_SongLoaded) MIDI_StopSong(); - _MIDI_Loop = loopflag; _MIDI_NumTracks = My_MIDI_NumTracks; _MIDI_Division = My_MIDI_Division; @@ -738,15 +772,10 @@ int MIDI_PlaySong(char *song, int loopflag) _MIDI_Reset = FALSE; - if (ASS_MIDISoundDriver == ASS_OPL3) - { - MV_MIDIRenderTempo = 100; - MV_MIDIRenderTimer = 0; - } - MIDI_SetTempo(120); - if (SoundDriver_MIDI_StartPlayback(ASS_MIDISoundDriver == ASS_OPL3 ? MV_RenderMIDI : _MIDI_ServiceRoutine) != MIDI_Ok) + // this can either stay like this, or I can add another field to the MIDI driver spec that holds the service callback + if (SoundDriver_MIDI_StartPlayback(ASS_MIDISoundDriver == ASS_OPL3 ? _MIDI_ServiceMultivoc : _MIDI_ServiceRoutine) != MIDI_Ok) return MIDI_DriverError; _MIDI_SongLoaded = TRUE; @@ -757,19 +786,11 @@ int MIDI_PlaySong(char *song, int loopflag) void MIDI_SetTempo(int tempo) { - MIDI_Tempo = tempo; SoundDriver_MIDI_SetTempo(tempo, _MIDI_Division); int const tickspersecond = tempo * _MIDI_Division / 60; _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond); } -void MIDI_SetDivision(int division) -{ - UNREFERENCED_PARAMETER(division); -} - -int MIDI_GetTempo(void) { return MIDI_Tempo; } - static void _MIDI_InitEMIDI(void) { int type = EMIDI_GeneralMIDI; @@ -777,10 +798,13 @@ static void _MIDI_InitEMIDI(void) switch (ASS_MIDISoundDriver) { case ASS_OPL3: - type = EMIDI_Adlib; + type = EMIDI_SoundBlaster; break; } + if (ASS_EMIDICard != -1) + type = ASS_EMIDICard; + _MIDI_ResetTracks(); _MIDI_TotalTime = 0; @@ -791,7 +815,7 @@ static void _MIDI_InitEMIDI(void) track *Track = _MIDI_TrackPtr; int tracknum = 0; - while ((tracknum < _MIDI_NumTracks) && (Track != NULL)) + while ((tracknum < _MIDI_NumTracks) && (Track != nullptr)) { _MIDI_Tick = 0; _MIDI_Beat = 1; @@ -894,7 +918,7 @@ static void _MIDI_InitEMIDI(void) case EMIDI_SONG_LOOP_END : if (c2 == EMIDI_END_LOOP_VALUE) { - Track->context[ 0 ].loopstart = NULL; + Track->context[ 0 ].loopstart = nullptr; Track->context[ 0 ].loopcount = 0; } break; @@ -983,30 +1007,3 @@ static void _MIDI_InitEMIDI(void) _MIDI_ResetTracks(); } -void MV_RenderMIDI(void) -{ - int16_t * buffer16 = (int16_t *)MV_MusicBuffer; - int const samples = MV_BufferSize >> 2; - - for (int i = 0; i < samples; i++) - { - Bit16s buf[2]; - while (MV_MIDIRenderTimer >= MV_MixRate) - { - if (MV_MIDIRenderTempo >= 0) - _MIDI_ServiceRoutine(); - MV_MIDIRenderTimer -= MV_MixRate; - } - if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo; - OPL3_GenerateResampled(&OPLMusic::chip, buf); - *buffer16++ = clamp(buf[0]<<1, INT16_MIN, INT16_MAX); - *buffer16++ = clamp(buf[1]<<1, INT16_MIN, INT16_MAX); - } -} - - -void MIDI_UpdateMusic(void) -{ - -} - diff --git a/source/audiolib/src/midi.h b/source/audiolib/src/midi.h index 584c4e6f2..f3de84b99 100644 --- a/source/audiolib/src/midi.h +++ b/source/audiolib/src/midi.h @@ -65,9 +65,5 @@ void MIDI_PauseSong(void); void MIDI_StopSong(void); int MIDI_PlaySong(char *song, int loopflag); void MIDI_SetTempo(int tempo); -int MIDI_GetTempo(void); -void MV_RenderMIDI(void); -void MIDI_UpdateMusic(void); -void MIDI_SetDivision(int division); #endif diff --git a/source/audiolib/src/multivoc.cpp b/source/audiolib/src/multivoc.cpp index b88aa18c0..afe626f9e 100644 --- a/source/audiolib/src/multivoc.cpp +++ b/source/audiolib/src/multivoc.cpp @@ -909,7 +909,7 @@ void MV_UnhookMusicRoutine(void) if (MV_MusicCallback) { MV_Lock(); - MV_MusicCallback = NULL; + MV_MusicCallback = nullptr; MV_MixMusic = FALSE; MV_Unlock(); } diff --git a/source/audiolib/src/music.cpp b/source/audiolib/src/music.cpp index 261d2ff81..ecd514c1c 100644 --- a/source/audiolib/src/music.cpp +++ b/source/audiolib/src/music.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "music.h" -#include "al_midi.h" #include "compat.h" #include "drivers.h" #include "midi.h" @@ -55,7 +54,7 @@ const char *MUSIC_ErrorString(int ErrorNumber) } -int MUSIC_Init(int SoundCard) +int MUSIC_Init(int SoundCard, int EMIDICard /*= -1*/) { int detected = 0; @@ -63,14 +62,7 @@ int MUSIC_Init(int SoundCard) { redetect: detected++; - -#if defined _WIN32 - SoundCard = ASS_WinMM; -#elif RENDERTYPESDL - SoundCard = ASS_SDL; -#else - SoundCard = ASS_NoSound; -#endif + SoundCard = ASS_OPL3; } if (SoundCard < 0 || SoundCard >= ASS_NumSoundCards) @@ -92,6 +84,7 @@ failed: } ASS_MIDISoundDriver = SoundCard; + ASS_EMIDICard = EMIDICard; int status = SoundDriver_MIDI_Init(&MUSIC_MidiFunctions); @@ -103,7 +96,7 @@ failed: goto failed; } - MV_Printf("successfully initialized %s!\n", SoundDriver_GetName(SoundCard)); + MV_Printf("%s\n", SoundDriver_GetName(SoundCard)); MIDI_SetMidiFuncs(&MUSIC_MidiFunctions); @@ -154,5 +147,4 @@ int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn /*= nu void MUSIC_Update(void) { - MIDI_UpdateMusic(); } diff --git a/source/audiolib/src/music_external.cpp b/source/audiolib/src/music_external.cpp index 456c56e3f..138e04d28 100644 --- a/source/audiolib/src/music_external.cpp +++ b/source/audiolib/src/music_external.cpp @@ -58,7 +58,6 @@ int MUSIC_Init(int SoundCard) g_musicPlayerCommandLine = getenv("EDUKE32_MUSIC_CMD"); UNREFERENCED_PARAMETER(SoundCard); - UNREFERENCED_PARAMETER(Address); if (g_musicPlayerReady) { @@ -126,7 +125,7 @@ int MUSIC_Init(int SoundCard) } g_musicFileNameArgvPos = numargs; g_musicPlayerArgv[numargs] = g_musicFileName; - g_musicPlayerArgv[numargs+1] = NULL; + g_musicPlayerArgv[numargs+1] = nullptr; #if 0 if (mprotect(g_musicPlayerArgv, sz, PROT_READ)==-1) // make argv and command string read-only @@ -151,44 +150,6 @@ int MUSIC_Shutdown(void) return MUSIC_Ok; } // MUSIC_Shutdown - -void MUSIC_SetMaxFMMidiChannel(int channel) -{ - UNREFERENCED_PARAMETER(channel); -} // MUSIC_SetMaxFMMidiChannel - -int MUSIC_Volume; - -void MUSIC_SetVolume(int volume) -{ - volume = max(0, volume); - volume = min(volume, 255); - - MUSIC_Volume = volume; -} // MUSIC_SetVolume - - -int MUSIC_GetVolume(void) -{ - return MUSIC_Volume; -} // MUSIC_GetVolume - - -void MUSIC_SetLoopFlag(int loopflag) -{ - UNREFERENCED_PARAMETER(loopflag); -} // MUSIC_SetLoopFlag - - -void MUSIC_Continue(void) -{ -} // MUSIC_Continue - - -void MUSIC_Pause(void) -{ -} // MUSIC_Pause - int MUSIC_StopSong(void) { if (!g_musicPlayerEnabled) @@ -205,9 +166,9 @@ int MUSIC_StopSong(void) ts.tv_nsec = 5000000; // sleep 5ms at most kill(g_musicPlayerHandle, SIGTERM); - nanosleep(&ts, NULL); + nanosleep(&ts, nullptr); - if (int ret = waitpid(g_musicPlayerHandle, NULL, WNOHANG|WUNTRACED) != g_musicPlayerHandle) + if (int ret = waitpid(g_musicPlayerHandle, nullptr, WNOHANG|WUNTRACED) != g_musicPlayerHandle) { if (ret==-1) initprintf("%s: waitpid: %s\n", __func__, strerror(errno)); @@ -218,7 +179,7 @@ int MUSIC_StopSong(void) initprintf("%s: SIGTERM timed out--trying SIGKILL\n", __func__); - if (waitpid(g_musicPlayerHandle, NULL, WUNTRACED)==-1) + if (waitpid(g_musicPlayerHandle, nullptr, WUNTRACED)==-1) initprintf("%s: waitpid: %s\n", __func__, strerror(errno)); } } @@ -241,7 +202,7 @@ static int MUSIC_PlayExternal() ZeroMemory(&pi,sizeof(pi)); si.cb = sizeof(si); - if (!CreateProcess(NULL,g_musicPlayerCommandLine,NULL,NULL,0,0,NULL,NULL,&si,&pi)) + if (!CreateProcess(nullptr,g_musicPlayerCommandLine,nullptr,nullptr,0,0,nullptr,nullptr,&si,&pi)) { MV_Printf("%s: CreateProcess: %s\n", __func__, windowsGetErrorMessage(GetLastError())); return MUSIC_Error; @@ -310,7 +271,7 @@ int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn /*= nu sa.sa_flags=0; sigemptyset(&sa.sa_mask); - if (sigaction(SIGCHLD, &sa, NULL)==-1) + if (sigaction(SIGCHLD, &sa, nullptr)==-1) initprintf("%s: sigaction: %s\n", __func__, strerror(errno)); sigchld_handler_set = 1; diff --git a/source/audiolib/src/pitch.h b/source/audiolib/src/pitch.h index 02fe9ae12..9b81e68f2 100644 --- a/source/audiolib/src/pitch.h +++ b/source/audiolib/src/pitch.h @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef PITCH_H_ #define PITCH_H_ -#include "inttypes.h" +#include uint32_t PITCH_GetScale(int pitchoffset); #endif diff --git a/source/duke3d/src/menus.cpp b/source/duke3d/src/menus.cpp index 665062de3..9ea14eed2 100644 --- a/source/duke3d/src/menus.cpp +++ b/source/duke3d/src/menus.cpp @@ -1166,16 +1166,16 @@ static MenuEntry_t ME_SOUND_NUMVOICES = MAKE_MENUENTRY( "Voices:", &MF_Redfont, #endif static char const *MEOSN_SOUND_MUSICDEVICE[] = { + "OPL3", #ifdef _WIN32 "Windows", #endif - "OPL3", }; static int32_t MEOSV_SOUND_MUSICDEVICE[] = { + ASS_OPL3, #ifdef _WIN32 ASS_WinMM, #endif - ASS_OPL3, }; static MenuOptionSet_t MEOS_SOUND_MUSICDEVICE = MAKE_MENUOPTIONSET( MEOSN_SOUND_MUSICDEVICE, MEOSV_SOUND_MUSICDEVICE, 0x2 ); diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index 79c508ccc..c6af33404 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "duke3d.h" #include "renderlayer.h" // for win_gethwnd() +#include "al_midi.h" #include #include "vfs.h" @@ -117,6 +118,19 @@ void S_MusicStartup(void) if (MUSIC_Init(ud.config.MusicDevice) == MUSIC_Ok || MUSIC_Init(0) == MUSIC_Ok || MUSIC_Init(1) == MUSIC_Ok) { MUSIC_SetVolume(mus_volume); + + // TODO: figure out why this produces garbage output +#if 0 + if (auto fil = kopen4load("d3dtimbr.tmb", 0) != -1) + { + int l = kfilelength(fil); + auto tmb = (uint8_t *)Xmalloc(l); + kread(fil, tmb, l); + OPLMusic::AL_RegisterTimbreBank(tmb); + Xfree(tmb); + kclose(fil); + } +#endif return; }