diff --git a/dc/dcmain.cpp b/dc/dcmain.cpp index bb1dc205217..e2ff7c56489 100644 --- a/dc/dcmain.cpp +++ b/dc/dcmain.cpp @@ -23,7 +23,6 @@ #include "stdafx.h" #include "scumm.h" #include "gui.h" -#include "sound.h" #include "dc.h" #include "icon.h" @@ -33,7 +32,7 @@ ScummDebugger debugger; Gui gui; Icon icon; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; /* CD Audio stubs */ diff --git a/gameDetector.cpp b/gameDetector.cpp index d74143ef865..e7a524e189a 100644 --- a/gameDetector.cpp +++ b/gameDetector.cpp @@ -23,8 +23,9 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" #include "gameDetector.h" - +#include "imuse.h" static const char USAGE_STRING[] = @@ -104,17 +105,11 @@ void GameDetector::parseCommandLine(int argc, char **argv) case 'm':{ if (*(s + 1) == '\0') goto ShowHelpAndExit; - SoundEngine *se = (SoundEngine *)_soundEngine; - - if (se) - se->set_music_volume(atoi(s + 1)); + _music_volume = atoi(s + 1); goto NextArg; } case 'r':{ - SoundEngine *se = (SoundEngine *)_soundEngine; - - if (se) - se->_mt32emulate = true; + _mt32emulate = true; break; } case 'e': @@ -208,8 +203,8 @@ bool GameDetector::parseMusicDriver(const char *s) { for(i=0; i!=ARRAYSIZE(music_drivers); i++,md++) { if (!scumm_stricmp(md->name, s)) { /* FIXME: when adlib driver is in use, propagate that to - * the Scumm class, and let it create an AdlibSoundDriver - * instead of MidiSoundDriver */ + * the IMuse class, and let it create an IMuseAdlib driver + * instead of IMuseGM driver */ if (md->id == -1) { _use_adlib = true; } diff --git a/gameDetector.h b/gameDetector.h index dc2d62b9f07..296ba6539db 100644 --- a/gameDetector.h +++ b/gameDetector.h @@ -34,6 +34,9 @@ public: bool _use_adlib; + byte _music_volume; + bool _mt32emulate; + uint16 _debugMode; uint16 _noSubtitles; uint16 _bootParam; @@ -41,7 +44,6 @@ public: char *_gameDataPath; int _gameTempo; - void *_soundEngine; int _midi_driver; char *_exe_name; const char *_gameText; diff --git a/gfx.cpp b/gfx.cpp index f9ba2248c3e..708e9c86092 100644 --- a/gfx.cpp +++ b/gfx.cpp @@ -584,7 +584,7 @@ void Scumm::unkVirtScreen4(int a) //setDirtyRange(0, 0, vs->height); //updateDirtyScreen(0); /* XXX: EGA_proc4(0); */ - warning("EGA_proc4"); /* FIXME */ +// warning("EGA_proc4"); /* FIXME */ break; case 134: unkScreenEffect5(0); diff --git a/gui.cpp b/gui.cpp index 76bd4a4dc9e..93b93e34646 100644 --- a/gui.cpp +++ b/gui.cpp @@ -21,8 +21,10 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" #include "gui.h" #include "guimaps.h" +#include "imuse.h" #ifdef _WIN32_WCE // Additional variables for Win32 specific GUI @@ -484,12 +486,13 @@ void Gui::handleSoundDialogCommand(int cmd) { if (cmd == 40 || cmd == 50) { if (cmd == 40) { - SoundEngine *se = (SoundEngine *)_s->_soundEngine; _s->_sound_volume_master = _gui_variables[0]; // Master _s->_sound_volume_music = _gui_variables[1]; // Music _s->_sound_volume_sfx = _gui_variables[2]; // SFX - se->set_music_volume(_s->_sound_volume_music); - se->set_master_volume(_s->_sound_volume_master); + + IMuse *imuse = _s->_imuse; + imuse->set_music_volume(_s->_sound_volume_music); + imuse->set_master_volume(_s->_sound_volume_master); registry_save(); } diff --git a/mac/mac.cpp b/mac/mac.cpp index 0704eafbb25..c43cf5dae86 100644 --- a/mac/mac.cpp +++ b/mac/mac.cpp @@ -31,7 +31,6 @@ #include "stdafx.h" #include "scumm.h" #include "gui.h" -#include "sound.h" #include "cdmusic.h" #include "mp3_cd.h" #include "gameDetector.h" @@ -138,7 +137,7 @@ int sel; Scumm *scumm; ScummDebugger debugger; Gui gui; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; OSystem _system; GameDetector detector; @@ -1025,7 +1024,6 @@ void InitScummStuff() scumm->_scale = detector._scale; scumm->_gameDataPath = detector._gameDataPath; scumm->_gameTempo = detector._gameTempo; - scumm->_soundEngine = detector._soundEngine; scumm->_videoMode = detector._videoMode; scumm->_exe_name = detector._exe_name; scumm->_gameId = detector._gameId; diff --git a/main.cpp b/main.cpp index aafcf2f666a..7176443fd13 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" #include "gameDetector.h" #include "gui.h" #include "simon/simon.h" @@ -57,7 +58,7 @@ int main(int argc, char *argv[]) { char *s = detector.getGameName(); - system->set_param(OSystem::PARAM_WINDOW_CAPTION, (long)s); + system->property(OSystem::PROP_SET_WINDOW_CAPTION, (long)s); free(s); } diff --git a/morphos/morphos.cpp b/morphos/morphos.cpp index 7f45eaabb22..e8e30418a07 100644 --- a/morphos/morphos.cpp +++ b/morphos/morphos.cpp @@ -64,7 +64,7 @@ Gui gui; OSystem _system; GameDetector detector; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; typedef void (*ScalerFunc)( uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height ); @@ -1879,7 +1879,6 @@ int main( int argc, char *argv[] ) scumm->_scale = detector._scale; scumm->_gameDataPath = detector._gameDataPath; scumm->_gameTempo = detector._gameTempo; - scumm->_soundEngine = detector._soundEngine; scumm->_videoMode = detector._videoMode; scumm->_exe_name = detector._exe_name; scumm->_gameId = detector._gameId; diff --git a/morphos/morphos_sound.cpp b/morphos/morphos_sound.cpp index 9abfb1c9500..99f55807fe7 100644 --- a/morphos/morphos_sound.cpp +++ b/morphos/morphos_sound.cpp @@ -40,7 +40,7 @@ extern int GetTicks(); extern Scumm scumm; -extern SoundEngine sound; +extern IMuse sound; extern SOUND_DRIVER_TYPE snd_driv; #define AHI_BUF_SIZE (8*1024) diff --git a/saveload.cpp b/saveload.cpp index 89a7a95539d..f71774c8997 100644 --- a/saveload.cpp +++ b/saveload.cpp @@ -22,6 +22,8 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" +#include "imuse.h" #ifdef _WIN32_WCE #define _MANAGE_OLD_SAVE @@ -742,9 +744,8 @@ void Scumm::saveOrLoad(Serializer * s) } } - if (_soundEngine) - ((SoundEngine *)_soundEngine)->save_or_load(s); - + if (_imuse) + _imuse->save_or_load(s, this); } void Scumm::saveLoadResource(Serializer * ser, int type, int idx) diff --git a/scumm.h b/scumm.h index 9debfb57631..277da70d0d1 100644 --- a/scumm.h +++ b/scumm.h @@ -21,6 +21,7 @@ #include "scummsys.h" #include "system.h" +#include "mixer.h" #ifdef COMPRESSED_SOUND_FILE #include @@ -35,6 +36,7 @@ class GameDetector; class Gui; class Scumm; +class IMuse; struct Actor; struct ScummDebugger; struct Serializer; @@ -549,7 +551,6 @@ enum MouseButtonStatus { #include "gfx.h" #include "boxes.h" -#include "sound.h" #include "akos.h" #include "smush.h" @@ -559,7 +560,7 @@ public: * That results in a shorter form of the opcode * on some architectures. */ OSystem *_system; - void *_soundEngine; + IMuse *_imuse; Gui *_gui; uint32 _features; VerbSlot *_verbs; @@ -939,10 +940,10 @@ public: void runVerbCode(int script, int entry, int a, int b, int16 *vars); void setVerbObject(uint room, uint object, uint verb); - /* Should be in Sound class */ - MixerChannel _mixer_channel[NUM_MIXER]; - int _gameTempo; + SoundMixer _mixer[1]; + +// MixerChannel _mixer_channel[NUM_MIXER]; byte _sfxMode; bool _use_adlib; int16 _sound_volume_master, _sound_volume_music, _sound_volume_sfx; @@ -982,13 +983,11 @@ public: int num_sound_effects; // SO3 MP3 compressed audio void pauseSounds(bool pause); - MixerChannel *allocateMixer(); bool isSfxFinished(); void playBundleSound(char *sound); void playSfxSound(void *sound, uint32 size, uint rate); - void playSfxSound_MP3(void *sound, uint32 size); + void playSfxSound_MP3(void *sound, uint32 size); void stopSfxSound(); - void mixWaves(int16 *sounds, int len); bool _useTalkAnims; uint16 _defaultTalkDelay; @@ -1682,7 +1681,6 @@ public: void updateCursor(); void animateCursor(); void updatePalette(); - static void on_generate_samples(void *s, int16 *samples, int len); }; class Scumm_v3 : public Scumm @@ -1798,6 +1796,7 @@ struct Serializer { }; + extern const uint32 IMxx_tags[]; extern const byte default_scale_table[768]; diff --git a/scummvm.cpp b/scummvm.cpp index adc66406307..be83449eb62 100644 --- a/scummvm.cpp +++ b/scummvm.cpp @@ -22,6 +22,8 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" +#include "imuse.h" #include "gui.h" #include "string.h" #include "gameDetector.h" @@ -1259,10 +1261,6 @@ void Scumm::launch() // _scummTimer = 0; } -void Scumm::on_generate_samples(void *s, int16 *samples, int len) { - ((Scumm*)s)->mixWaves(samples, len); -} - Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst) { Scumm *scumm; @@ -1281,17 +1279,18 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst) scumm->_system = syst; /* This initializes SDL */ - syst->init_size(320,200, OSystem::SOUND_16BIT); - syst->set_param(OSystem::PARAM_OPEN_CD, detector->_cdrom); + syst->init_size(320,200); + syst->property(OSystem::PROP_OPEN_CD, detector->_cdrom); - syst->set_sound_proc(scumm, on_generate_samples); + /* bind the mixer to the system => mixer will be invoked + * automatically when samples need to be generated */ + scumm->_mixer->bind_to_system(syst); + scumm->_mixer->set_volume(128); scumm->_fullScreen = detector->_fullScreen; scumm->_debugMode = detector->_debugMode; scumm->_bootParam = detector->_bootParam; scumm->_gameDataPath = detector->_gameDataPath; - scumm->_gameTempo = detector->_gameTempo; - scumm->_soundEngine = detector->_soundEngine; scumm->_exe_name = detector->_exe_name; scumm->_gameId = detector->_gameId; scumm->_gameText = detector->_gameText; @@ -1301,20 +1300,21 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst) scumm->_cdrom = detector->_cdrom; { - SoundDriver *sdriv; - SoundEngine *seng; + IMuse *imuse; scumm->_use_adlib = detector->_use_adlib; - - if (!detector->_use_adlib) { - MidiDriver *midi = detector->createMidi(); - sdriv = new MidiSoundDriver; - ((MidiSoundDriver*)sdriv)->midiSetDriver(midi); + + if (detector->_use_adlib) { + imuse = IMuse::create_adlib(syst, scumm->_mixer); } else { - sdriv = new AdlibSoundDriver; + imuse = IMuse::create_midi(syst, detector->createMidi()); } - seng = new SoundEngine; - seng->initialize(scumm, sdriv); + + imuse->property(IMuse::PROP_MT32_EMULATE, detector->_mt32emulate); + if (detector->_gameTempo != 0) + imuse->property(IMuse::PROP_TEMPO_BASE, detector->_gameTempo); + + scumm->_imuse = imuse; } scumm->delta = 6; diff --git a/scummvm.dsp b/scummvm.dsp index 42d7dba044a..66bc3cc55f6 100644 --- a/scummvm.dsp +++ b/scummvm.dsp @@ -121,28 +121,32 @@ LINK32=link.exe # PROP Default_Filter "" # Begin Source File -SOURCE=.\sound\adlib.cpp -# End Source File -# Begin Source File - SOURCE=.\sound\fmopl.cpp # End Source File # Begin Source File -SOURCE=.\sound\gmidi.cpp -# End Source File -# Begin Source File - -SOURCE=.\sound\gmidi.h -# End Source File -# Begin Source File - SOURCE=.\sound\imuse.cpp # End Source File # Begin Source File +SOURCE=.\sound\imuse.h +# End Source File +# Begin Source File + SOURCE=.\sound\mididrv.cpp # End Source File +# Begin Source File + +SOURCE=.\sound\mididrv.h +# End Source File +# Begin Source File + +SOURCE=.\sound\mixer.cpp +# End Source File +# Begin Source File + +SOURCE=.\sound\mixer.h +# End Source File # End Group # Begin Group "v3" @@ -512,10 +516,6 @@ SOURCE=.\smush.h # End Source File # Begin Source File -SOURCE=.\sound.h -# End Source File -# Begin Source File - SOURCE=.\StdAfx.h # End Source File # Begin Source File diff --git a/sdl.cpp b/sdl.cpp index eb4460c59ea..af3997c37b7 100644 --- a/sdl.cpp +++ b/sdl.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" #include "SDL_thread.h" #include "gameDetector.h" @@ -16,7 +17,7 @@ public: // Set the size of the video bitmap. // Typically, 320x200 - void init_size(uint w, uint h, byte sound); + void init_size(uint w, uint h); // Draw a bitmap to screen. // The screen will not be updated to reflect the new bitmap @@ -51,13 +52,13 @@ public: bool poll_event(Event *event); // Set function that generates samples - void set_sound_proc(void *param, SoundProc *proc); + void set_sound_proc(void *param, SoundProc *proc, byte sound); // Quit void quit(); // Set a parameter - uint32 set_param(int param, uint32 value); + uint32 property(int param, uint32 value); static OSystem *create(int gfx_mode, bool full_screen); @@ -108,9 +109,6 @@ private: int scaling; - SoundProc *_sound_proc; - void *_sound_param; - struct MousePos { int16 x,y,w,h; }; @@ -197,14 +195,6 @@ void OSystem_SDL::set_palette(const byte *colors, uint start, uint num) { SDL_SetColors(sdl_screen, base, start, num); } -void OSystem_SDL::fill_sound(void *userdata, Uint8 * stream, int len) { - OSystem_SDL *os = (OSystem_SDL*)userdata; - if (os->_sound_proc) - os->_sound_proc(os->_sound_param, (int16*)stream, len>>1); - else - memset(stream, 0x0, len); -} - void OSystem_SDL::load_gfx_mode() { force_full = true; scaling = 1; @@ -307,24 +297,10 @@ void OSystem_SDL::unload_gfx_mode() { } } -void OSystem_SDL::init_size(uint w, uint h, byte sound) { - SDL_AudioSpec desired; - +void OSystem_SDL::init_size(uint w, uint h) { if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) error("320x200 is the only game resolution supported"); - /* init sound */ - if (sound != SOUND_NONE) { - desired.freq = SAMPLES_PER_SEC; - desired.format = sound==SOUND_8BIT ? AUDIO_U8 : AUDIO_S16SYS; - desired.channels = 1; - desired.samples = 2048; - desired.callback = fill_sound; - desired.userdata = this; - SDL_OpenAudio(&desired, NULL); - SDL_PauseAudio(0); - } - /* allocate palette, it needs to be persistent across * driver changes, so i'll alloc it here */ _cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256); @@ -668,7 +644,7 @@ bool OSystem_SDL::poll_event(Event *event) { /* internal keypress? */ if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) { - set_param(PARAM_TOGGLE_FULLSCREEN, 0); + property(PROP_TOGGLE_FULLSCREEN, 0); break; } @@ -679,7 +655,7 @@ bool OSystem_SDL::poll_event(Event *event) { if (b == (KBD_CTRL|KBD_ALT) && ev.key.keysym.sym>='1' && ev.key.keysym.sym<='6') { - set_param(PARAM_HOTSWAP_GFX_MODE, ev.key.keysym.sym - '1'); + property(PROP_SET_GFX_MODE, ev.key.keysym.sym - '1'); break; } @@ -733,9 +709,19 @@ bool OSystem_SDL::poll_event(Event *event) { } } -void OSystem_SDL::set_sound_proc(void *param, SoundProc *proc) { - _sound_proc = proc; - _sound_param = param; +void OSystem_SDL::set_sound_proc(void *param, SoundProc *proc, byte format) { + SDL_AudioSpec desired; + + /* only one format supported at the moment */ + + desired.freq = SAMPLES_PER_SEC; + desired.format = AUDIO_S16SYS; + desired.channels = 1; + desired.samples = 2048; + desired.callback = proc; + desired.userdata = param; + SDL_OpenAudio(&desired, NULL); + SDL_PauseAudio(0); } @@ -806,10 +792,10 @@ void OSystem_SDL::hotswap_gfx_mode() { OSystem_SDL::update_screen(); } -uint32 OSystem_SDL::set_param(int param, uint32 value) { +uint32 OSystem_SDL::property(int param, uint32 value) { switch(param) { - case PARAM_TOGGLE_FULLSCREEN: + case PROP_TOGGLE_FULLSCREEN: _full_screen ^= true; if (!SDL_WM_ToggleFullScreen(sdl_hwscreen)) { @@ -818,11 +804,11 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) { } return 1; - case PARAM_WINDOW_CAPTION: + case PROP_SET_WINDOW_CAPTION: SDL_WM_SetCaption((char*)value, (char*)value); return 1; - case PARAM_OPEN_CD: + case PROP_OPEN_CD: if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) cdrom = NULL; else { @@ -834,7 +820,7 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) { } break; - case PARAM_HOTSWAP_GFX_MODE: + case PROP_SET_GFX_MODE: if (value >= 6) return 0; @@ -843,9 +829,12 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) { return 1; - case PARAM_SHOW_DEFAULT_CURSOR: + case PROP_SHOW_DEFAULT_CURSOR: SDL_ShowCursor(value ? SDL_ENABLE : SDL_DISABLE); break; + + case PROP_GET_SAMPLE_RATE: + return SAMPLES_PER_SEC; } return 0; @@ -1027,7 +1016,7 @@ void OSystem_SDL::undraw_mouse() { class OSystem_NULL : public OSystem { public: void set_palette(const byte *colors, uint start, uint num) {} - void init_size(uint w, uint h, byte sound); + void init_size(uint w, uint h); void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) {} void update_screen() {} bool show_mouse(bool visible) { return false; } @@ -1038,9 +1027,9 @@ public: void delay_msecs(uint msecs); void *create_thread(ThreadProc *proc, void *param) { return NULL; } bool poll_event(Event *event) { return false; } - void set_sound_proc(void *param, SoundProc *proc) {} + void set_sound_proc(void *param, SoundProc *proc, byte sound) {} void quit() { exit(1); } - uint32 set_param(int param, uint32 value) { return 0; } + uint32 property(int param, uint32 value) { return 0; } static OSystem *create(int gfx_mode, bool full_screen); private: diff --git a/simon/midi.cpp b/simon/midi.cpp index d48a03eb48b..a83ed657079 100644 --- a/simon/midi.cpp +++ b/simon/midi.cpp @@ -23,7 +23,8 @@ #include "stdafx.h" #include "scummsys.h" #include "system.h" -#include "gmidi.h" +#include "mididrv.h" +#include "mixer.h" #include "simon.h" void MidiPlayer::read_from_file(void *dst, uint size) { diff --git a/simon/simon.cpp b/simon/simon.cpp index ada5890267f..f673a65e160 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -23,8 +23,10 @@ #include "stdafx.h" #include "scummsys.h" #include "system.h" +#include "mixer.h" #include "simon.h" + #include #include #ifdef WIN32 @@ -5034,8 +5036,7 @@ void SimonState::vc_29_stop_all_sounds() { /* XXX: implement */ // warning("vc_29_stop_all_sounds unimplemented"); - _voice_size = 0; - _sound_size = 0; + _mixer->stop_all(); } void SimonState::vc_30_set_base_delay() { @@ -6518,7 +6519,7 @@ bool SimonState::vc_59_helper() { #else if (_voice_file==NULL) return false; - return _voice_size == 0; + return _voice_sound == 0; #endif } @@ -6574,9 +6575,8 @@ void SimonState::readSfxFile(const char *filename) { rewind(in); - /* if a sound is playing, stop it */ - _sound_size = 0; - + /* stop all sounds */ + _mixer->stop_all(); if (_sfx_heap) free(_sfx_heap); @@ -6595,10 +6595,6 @@ void SimonState::readSfxFile(const char *filename) { vc_29_stop_all_sounds(); - /* if a sound is playing, stop it */ - _sound_size = 0; - - if (_sfx_heap) free(_sfx_heap); res = atoi(filename + 6) + gss->SOUND_INDEX_BASE - 1; @@ -7386,7 +7382,7 @@ void SimonState::openGameFile() { loadIconFile(); - _system->init_size(320,200,OSystem::SOUND_8BIT); + _system->init_size(320,200); startUp(1); } @@ -7411,6 +7407,7 @@ void SimonState::runSubroutine101() { startUp_helper_2(); } +#if 0 void SimonState::generateSound(byte *ptr, int len) { uint cur; @@ -7438,10 +7435,11 @@ void SimonState::generateSound(byte *ptr, int len) { _sound_ptr += cur; } } +#endif -static void fill_sound(void *userdata, int16 *stream, int len) { - ((SimonState*)userdata)->generateSound((byte*)stream, len*2); -} +//static void fill_sound(void *userdata, int16 *stream, int len) { +// ((SimonState*)userdata)->generateSound((byte*)stream, len*2); +//} void SimonState::dx_copy_rgn_from_3_to_2(uint b, uint r, uint y, uint x) { byte *dst, *src; @@ -7579,8 +7577,10 @@ void SimonState::go(OSystem *syst, MidiDriver *driver) { _vga_base_delay = 1; _vk_t_toggle = true; - _system->set_param(OSystem::PARAM_SHOW_DEFAULT_CURSOR, 1); - _system->set_sound_proc(this, fill_sound); + _system->property(OSystem::PROP_SHOW_DEFAULT_CURSOR, 1); + + _mixer->bind_to_system(_system); + _mixer->set_volume(256); while(1) { hitarea_stuff(); @@ -7915,11 +7915,11 @@ void SimonState::playVoice(uint voice) { // assert(voice < 14496/4); - _voice_size = 0; - if (_voice_offsets == NULL) return; + _mixer->stop(_voice_sound); + fseek(_voice_file, _voice_offsets[voice], SEEK_SET); if (fread(&wave_hdr, sizeof(wave_hdr), 1, _voice_file)!=1 || @@ -7937,7 +7937,8 @@ void SimonState::playVoice(uint voice) { return; } - _voice_size = data[1]; + _mixer->play_raw(&_voice_sound, _voice_file, data[1], wave_hdr.samples_per_sec, + SoundMixer::FLAG_FILE|SoundMixer::FLAG_UNSIGNED); } @@ -7945,8 +7946,7 @@ void SimonState::playSound(uint sound) { if (_game & GAME_WIN) { byte *p; - /* stop any currently playing sound */ - _sound_size = 0; + _mixer->stop(_playing_sound); /* Check if _sfx_heap is NULL */ if (_sfx_heap == NULL) { @@ -7968,8 +7968,7 @@ void SimonState::playSound(uint sound) { p++; } - _sound_ptr = p + 8; - _sound_size = ((uint32*)p)[1]; + _mixer->play_raw(&_playing_sound, p+8,*(uint32*)(p+4),22050,SoundMixer::FLAG_UNSIGNED); } else { warning("playSound(%d)", sound); } diff --git a/simon/simon.h b/simon/simon.h index a4067dad265..a4391e482f6 100644 --- a/simon/simon.h +++ b/simon/simon.h @@ -1,12 +1,22 @@ -/* Copyright ©2002, The ScummVM Team. +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 The ScummVM project + * + * 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. + * + * $Header$ * - * Current status: - * Save/Load dialog doesn't work. You can still save, but only to ONE slot. - * There is possibly one or two problems that makes it impossible to finish SIMON1WIN. - * Sound & Music only works with SIMON1WIN. - * SIMON1DOS works, but without sound & music. - * Simon 2 works a little. - * The code only compiles in win32. It's currently not alignment safe and not endian safe. */ /* GFX Settings. Sound & Music only works properly with SIMON1WIN */ @@ -504,10 +514,10 @@ public: uint _invoke_timer_callback; - uint32 _voice_size; +// uint32 _voice_size; - uint32 _sound_size; - byte *_sound_ptr; +// uint32 _sound_size; +// byte *_sound_ptr; uint _vga_sprite_changed; @@ -542,6 +552,8 @@ public: byte _fcs_data_1[8]; bool _fcs_data_2[8]; + SoundMixer _mixer[1]; + ThreeValues _threevalues_1, _threevalues_2, _threevalues_3, _threevalues_4; int _free_string_slot; @@ -574,6 +586,9 @@ public: int _num_screen_updates; int _vga_tick_counter; + PlayingSoundHandle _playing_sound; + PlayingSoundHandle _voice_sound; + int _timer_id; FILE *_dump_file; @@ -994,7 +1009,8 @@ public: void playVoice(uint voice); void playSound(uint sound); - void generateSound(byte *ptr, int len); + +// void generateSound(byte *ptr, int len); void playMusic(uint music); diff --git a/simon/simonsys.cpp b/simon/simonsys.cpp index 047a672f712..7d6d54b6c5d 100644 --- a/simon/simonsys.cpp +++ b/simon/simonsys.cpp @@ -23,6 +23,7 @@ #include "stdafx.h" #include "scummsys.h" #include "system.h" +#include "mixer.h" #include "simon.h" #include diff --git a/sound.cpp b/sound.cpp index 22c14dbad25..1085088abfc 100644 --- a/sound.cpp +++ b/sound.cpp @@ -22,6 +22,8 @@ #include "stdafx.h" #include "scumm.h" +#include "mididrv.h" +#include "imuse.h" #include "cdmusic.h" #ifdef _WIN32_WCE @@ -54,7 +56,7 @@ void Scumm::processSoundQues() int i, j; int num; int16 data[16]; - SoundEngine *se; + IMuse *se; processSfxQueues(); @@ -77,7 +79,7 @@ void Scumm::processSoundQues() data[j] = _soundQue[i + j]; i += num; - se = (SoundEngine *)_soundEngine; + se = _imuse; #if 0 debug(1, "processSoundQues(%d,%d,%d,%d,%d,%d,%d,%d,%d)", data[0] >> 8, @@ -100,7 +102,7 @@ void Scumm::processSoundQues() void Scumm::playSound(int sound) { byte *ptr; - SoundEngine *se = (SoundEngine *)_soundEngine; + IMuse *se = _imuse; ptr = getResourceAddress(rtSound, sound); if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('SOUN')) { @@ -253,7 +255,7 @@ bool Scumm::isMouthSyncOff(uint pos) int Scumm::isSoundRunning(int sound) { - SoundEngine *se; + IMuse *se; int i; if (sound == current_cd_sound) @@ -271,7 +273,7 @@ int Scumm::isSoundRunning(int sound) if (!isResourceLoaded(rtSound, sound)) return 0; - se = (SoundEngine *)_soundEngine; + se = _imuse; if (!se) return 0; return se->get_sound_status(sound); @@ -300,7 +302,7 @@ bool Scumm::isSoundInQueue(int sound) void Scumm::stopSound(int a) { - SoundEngine *se; + IMuse *se; int i; if (a == current_cd_sound) { @@ -308,7 +310,7 @@ void Scumm::stopSound(int a) cd_stop(); } - se = (SoundEngine *)_soundEngine; + se = _imuse; if (se) se->stop_sound(a); @@ -319,7 +321,7 @@ void Scumm::stopSound(int a) void Scumm::stopAllSounds() { - SoundEngine *se = (SoundEngine *)_soundEngine; + IMuse *se = _imuse; if (current_cd_sound != 0) { current_cd_sound = 0; @@ -376,7 +378,7 @@ void Scumm::talkSound(uint32 a, uint32 b, int mode) void Scumm::setupSound() { - SoundEngine *se = (SoundEngine *)_soundEngine; + IMuse *se = _imuse; if (se) { se->setBase(res.address[rtSound]); if (se->get_music_volume() == 0) @@ -392,7 +394,7 @@ void Scumm::setupSound() void Scumm::pauseSounds(bool pause) { - SoundEngine *se = (SoundEngine *)_soundEngine; + IMuse *se = _imuse; if (se) se->pause(pause); _soundsPaused = pause; @@ -562,85 +564,17 @@ void *Scumm::openSfxFile() return file; } -MixerChannel *Scumm::allocateMixer() -{ - int i; - MixerChannel *mc = _mixer_channel; - for (i = 0; i < NUM_MIXER; i++, mc++) { - if (!mc->_sfx_sound) - return mc; - } - return NULL; -} - void Scumm::stopSfxSound() { - MixerChannel *mc = _mixer_channel; - int i; - for (i = 0; i < NUM_MIXER; i++, mc++) { - if (mc->_sfx_sound) - mc->clear(); - } + _mixer->stop_all(); } bool Scumm::isSfxFinished() { - int i; - for (i = 0; i < NUM_MIXER; i++) - if (_mixer_channel[i]._sfx_sound) - return false; - return true; + return !_mixer->has_active_channel(); } -#ifdef COMPRESSED_SOUND_FILE -void Scumm::playSfxSound_MP3(void *sound, uint32 size) -{ - MixerChannel *mc = allocateMixer(); - - if (!mc) { - warning("No mixer channel available"); - return; - } - - mc->type = MIXER_MP3; - mc->_sfx_sound = sound; - - mad_stream_init(&mc->sound_data.mp3.stream); - - - -#ifdef _WIN32_WCE - - // 11 kHz on WinCE - - mad_stream_options((mad_stream *) & mc->sound_data.mp3.stream, - MAD_OPTION_HALFSAMPLERATE); - -#endif - - - mad_frame_init(&mc->sound_data.mp3.frame); - mad_synth_init(&mc->sound_data.mp3.synth); - mc->sound_data.mp3.position = 0; - mc->sound_data.mp3.pos_in_frame = 0xFFFFFFFF; - mc->sound_data.mp3.size = size; - /* This variable is the number of samples to cut at the start of the MP3 - file. This is needed to have lip-sync as the MP3 file have some miliseconds - of blank at the start (as, I suppose, the MP3 compression algorithm need to - have some silence at the start to really be efficient and to not distort - too much the start of the sample). - - This value was found by experimenting out. If you recompress differently your - .SO3 file, you may have to change this value. - - When using Lame, it seems that the sound starts to have some volume about 50 ms - from the start of the sound => we skip about 1024 samples. - */ - mc->sound_data.mp3.silence_cut = 1024; -} -#endif - void Scumm::playBundleSound(char *sound) { warning("playBundleSound: %s", sound); @@ -648,304 +582,8 @@ void Scumm::playBundleSound(char *sound) void Scumm::playSfxSound(void *sound, uint32 size, uint rate) { - MixerChannel *mc = allocateMixer(); - - if (!mc) { - warning("No mixer channel available"); - return; - } - - mc->type = MIXER_STANDARD; - mc->_sfx_sound = sound; - mc->sound_data.standard._sfx_pos = 0; - mc->sound_data.standard._sfx_fp_pos = 0; - -#ifdef _WIN32_WCE - mc->sound_data.standard._sfx_fp_speed = (1 << 16) * rate / 11025; -#else - mc->sound_data.standard._sfx_fp_speed = (1 << 16) * rate / 22050; -#endif - while (size & 0xFFFF0000) - size >>= 1, rate >>= 1; - - -#ifdef _WIN32_WCE - mc->sound_data.standard._sfx_size = size * 11025 / rate; -#else - mc->sound_data.standard._sfx_size = size * 22050 / rate; -#endif + _mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_AUTOFREE); } -#ifdef COMPRESSED_SOUND_FILE -static inline int scale_sample(mad_fixed_t sample) -{ - /* round */ - sample += (1L << (MAD_F_FRACBITS - 16)); - /* clip */ - if (sample >= MAD_F_ONE) - sample = MAD_F_ONE - 1; - else if (sample < -MAD_F_ONE) - sample = -MAD_F_ONE; - /* quantize and scale to not saturate when mixing a lot of channels */ - return sample >> (MAD_F_FRACBITS + 2 - 16); -} -#endif - -void MixerChannel::mix(int16 * data, uint32 len) -{ - if (!_sfx_sound) - return; - -#ifdef COMPRESSED_SOUND_FILE - if (type == MIXER_STANDARD) { -#endif - int8 *s; - uint32 fp_pos, fp_speed; - - if (len > sound_data.standard._sfx_size) - len = sound_data.standard._sfx_size; - sound_data.standard._sfx_size -= len; - - s = (int8 *) _sfx_sound + sound_data.standard._sfx_pos; - fp_pos = sound_data.standard._sfx_fp_pos; - fp_speed = sound_data.standard._sfx_fp_speed; - - do { - fp_pos += fp_speed; - *data++ += (*s << 6); - s += fp_pos >> 16; - fp_pos &= 0x0000FFFF; - } while (--len); - - sound_data.standard._sfx_pos = s - (int8 *) _sfx_sound; - sound_data.standard._sfx_fp_speed = fp_speed; - sound_data.standard._sfx_fp_pos = fp_pos; - - if (!sound_data.standard._sfx_size) - clear(); -#ifdef COMPRESSED_SOUND_FILE - } else { - if (type == MIXER_MP3) { - mad_fixed_t const *ch; - while (1) { - ch = - sound_data.mp3.synth.pcm.samples[0] + sound_data.mp3.pos_in_frame; - while ((sound_data.mp3.pos_in_frame < sound_data.mp3.synth.pcm.length) - && (len > 0)) { - if (sound_data.mp3.silence_cut > 0) { - sound_data.mp3.silence_cut--; - } else { - *data++ += scale_sample(*ch++); - len--; - } - sound_data.mp3.pos_in_frame++; - } - if (len == 0) - return; - - if (sound_data.mp3.position >= sound_data.mp3.size) { - clear(); - return; - } - - mad_stream_buffer(&sound_data.mp3.stream, - ((unsigned char *)_sfx_sound) + - sound_data.mp3.position, - sound_data.mp3.size + MAD_BUFFER_GUARD - - sound_data.mp3.position); - - if (mad_frame_decode(&sound_data.mp3.frame, &sound_data.mp3.stream) == - -1) { - /* End of audio... */ - if (sound_data.mp3.stream.error == MAD_ERROR_BUFLEN) { - clear(); - return; - } else if (!MAD_RECOVERABLE(sound_data.mp3.stream.error)) { - error("MAD frame decode error !"); - } - } - mad_synth_frame(&sound_data.mp3.synth, &sound_data.mp3.frame); - sound_data.mp3.pos_in_frame = 0; - sound_data.mp3.position = - (unsigned char *)sound_data.mp3.stream.next_frame - - (unsigned char *)_sfx_sound; - } - } else if (type == MIXER_MP3_CDMUSIC) { - mad_fixed_t const *ch; - mad_timer_t frame_duration; - static long last_pos = 0; - - if (!sound_data.mp3_cdmusic.playing) - return; - - while (1) { - - // See if we just skipped - if (ftell(sound_data.mp3_cdmusic.file) != last_pos) { - int skip_loop; - - // Read the new data - memset(_sfx_sound, 0, - sound_data.mp3_cdmusic.buffer_size + MAD_BUFFER_GUARD); - sound_data.mp3_cdmusic.size = - fread(_sfx_sound, 1, sound_data.mp3_cdmusic.buffer_size, - sound_data.mp3_cdmusic.file); - if (!sound_data.mp3_cdmusic.size) { - sound_data.mp3_cdmusic.playing = false; - return; - } - last_pos = ftell(sound_data.mp3_cdmusic.file); - // Resync - mad_stream_buffer(&sound_data.mp3_cdmusic.stream, - (unsigned char *)_sfx_sound, - sound_data.mp3_cdmusic.size); - skip_loop = 2; - while (skip_loop != 0) { - if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, - &sound_data.mp3_cdmusic.stream) == 0) { - /* Do not decrease duration - see if it's a problem */ - skip_loop--; - if (skip_loop == 0) { - mad_synth_frame(&sound_data.mp3_cdmusic.synth, - &sound_data.mp3_cdmusic.frame); - } - } else { - if (!MAD_RECOVERABLE(sound_data.mp3_cdmusic.stream.error)) { - debug(1, "Unrecoverable error while skipping !"); - sound_data.mp3_cdmusic.playing = false; - return; - } - } - } - // We are supposed to be in synch - mad_frame_mute(&sound_data.mp3_cdmusic.frame); - mad_synth_mute(&sound_data.mp3_cdmusic.synth); - // Resume decoding - if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, - &sound_data.mp3_cdmusic.stream) == 0) { - sound_data.mp3_cdmusic.position = - (unsigned char *)sound_data.mp3_cdmusic.stream.next_frame - - (unsigned char *)_sfx_sound; - sound_data.mp3_cdmusic.pos_in_frame = 0; - } else { - sound_data.mp3_cdmusic.playing = false; - return; - } - } - // Get samples, play samples ... - - ch = sound_data.mp3_cdmusic.synth.pcm.samples[0] + - sound_data.mp3_cdmusic.pos_in_frame; - while ((sound_data.mp3_cdmusic.pos_in_frame < - sound_data.mp3_cdmusic.synth.pcm.length) && (len > 0)) { - *data++ += scale_sample(*ch++); - len--; - sound_data.mp3_cdmusic.pos_in_frame++; - } - if (len == 0) { - return; - } - // See if we have finished - // May be incorrect to check the size at the end of a frame but I suppose - // they are short enough :) - - frame_duration = sound_data.mp3_cdmusic.frame.header.duration; - - mad_timer_negate(&frame_duration); - mad_timer_add(&sound_data.mp3_cdmusic.duration, frame_duration); - if (mad_timer_compare(sound_data.mp3_cdmusic.duration, mad_timer_zero) - < 0) { - sound_data.mp3_cdmusic.playing = false; - } - - if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, - &sound_data.mp3_cdmusic.stream) == -1) { - - if (sound_data.mp3_cdmusic.stream.error == MAD_ERROR_BUFLEN) { - int not_decoded; - - if (!sound_data.mp3_cdmusic.stream.next_frame) { - memset(_sfx_sound, 0, - sound_data.mp3_cdmusic.buffer_size + MAD_BUFFER_GUARD); - sound_data.mp3_cdmusic.size = - fread(_sfx_sound, 1, sound_data.mp3_cdmusic.buffer_size, - sound_data.mp3_cdmusic.file); - sound_data.mp3_cdmusic.position = 0; - not_decoded = 0; - } else { - not_decoded = sound_data.mp3_cdmusic.stream.bufend - - sound_data.mp3_cdmusic.stream.next_frame; - memcpy(_sfx_sound, sound_data.mp3_cdmusic.stream.next_frame, - not_decoded); - - sound_data.mp3_cdmusic.size = - fread((unsigned char *)_sfx_sound + not_decoded, 1, - sound_data.mp3_cdmusic.buffer_size - not_decoded, - sound_data.mp3_cdmusic.file); - } - last_pos = ftell(sound_data.mp3_cdmusic.file); - sound_data.mp3_cdmusic.stream.error = MAD_ERROR_NONE; - // Restream - mad_stream_buffer(&sound_data.mp3_cdmusic.stream, - (unsigned char *)_sfx_sound, - sound_data.mp3_cdmusic.size + not_decoded); - if (mad_frame_decode - (&sound_data.mp3_cdmusic.frame, - &sound_data.mp3_cdmusic.stream) == -1) { - debug(1, "Error decoding after restream %d !", - sound_data.mp3.stream.error); - } - } else if (!MAD_RECOVERABLE(sound_data.mp3.stream.error)) { - error("MAD frame decode error in MP3 CDMUSIC !"); - } - } - - mad_synth_frame(&sound_data.mp3_cdmusic.synth, - &sound_data.mp3_cdmusic.frame); - sound_data.mp3_cdmusic.pos_in_frame = 0; - sound_data.mp3_cdmusic.position = - (unsigned char *)sound_data.mp3_cdmusic.stream.next_frame - - (unsigned char *)_sfx_sound; - } - } - } -#endif -} - -void MixerChannel::clear() -{ - free(_sfx_sound); - _sfx_sound = NULL; - -#ifdef COMPRESSED_SOUND_FILE - if (type == MIXER_MP3) { - mad_synth_finish(&sound_data.mp3.synth); - mad_frame_finish(&sound_data.mp3.frame); - mad_stream_finish(&sound_data.mp3.stream); - } -#endif -} - -void Scumm::mixWaves(int16 * sounds, int len) -{ - int i; - - memset(sounds, 0, len * sizeof(int16)); - - if (_soundsPaused) - return; - - SoundEngine *se = (SoundEngine *)_soundEngine; - if (se) { - se->driver()->generate_samples(sounds, len); - } - - for (i = NUM_MIXER - 1; i >= 0; i--) { - _mixer_channel[i].mix(sounds, len); - } - - if (_soundsPaused2) - memset(sounds, 0x0, len * sizeof(int16)); -} diff --git a/sound.h b/sound.h deleted file mode 100644 index 2d4ba7b7e84..00000000000 --- a/sound.h +++ /dev/null @@ -1,645 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 The ScummVM project - * - * 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. - * - */ - - #ifndef SOUND_H - #define SOUND_H - -#include "gmidi.h" /* General Midi */ - -struct MP3OffsetTable { /* Compressed Sound (.SO3) */ - int org_offset; - int new_offset; - int num_tags; - int compressed_size; -}; - -typedef enum { /* Mixer types */ - MIXER_STANDARD, - MIXER_MP3, - MIXER_MP3_CDMUSIC -} MixerType; - -struct MixerChannel { /* Mixer Channel */ - void *_sfx_sound; - MixerType type; - union { - struct { - uint32 _sfx_pos; - uint32 _sfx_size; - uint32 _sfx_fp_speed; - uint32 _sfx_fp_pos; - } standard; -#ifdef COMPRESSED_SOUND_FILE - struct { - struct mad_stream stream; - struct mad_frame frame; - struct mad_synth synth; - uint32 silence_cut; - uint32 pos_in_frame; - uint32 position; - uint32 size; - } mp3; - struct { - struct mad_stream stream; - struct mad_frame frame; - struct mad_synth synth; - uint32 pos_in_frame; - uint32 position; - uint32 size; - uint32 buffer_size; - mad_timer_t duration; - bool playing; - FILE *file; - } mp3_cdmusic; -#endif - } sound_data; - void mix(int16 *data, uint32 len); - void clear(); -}; - -int clamp(int val, int min, int max); - - - -struct FM_OPL; -struct Part; -struct MidiChannel; -struct MidiChannelAdl; -struct MidiChannelGM; -struct VolumeFader; -struct Player; -struct HookDatas; -struct SoundEngine; -struct SoundDriver; -struct Instrument; -struct AdlibSoundDriver; -struct MidiSoundDriver; - -struct Struct10 { - byte active; - int16 cur_val; - int16 count; - uint16 param; - int16 start_value; - byte loop; - byte table_a[4]; - byte table_b[4]; - int8 unk3; - int8 modwheel; - int8 modwheel_last; - uint16 speed_lo_max; - uint16 num_steps; - int16 speed_hi; - int8 direction; - uint16 speed_lo; - uint16 speed_lo_counter; -}; - -struct Struct11 { - int16 modify_val; - byte param,flag0x40,flag0x10; - Struct10 *s10; -}; - -struct InstrumentExtra { - byte a,b,c,d,e,f,g,h; -}; - -struct Instrument { - byte flags_1; - byte oplvl_1; - byte atdec_1; - byte sustrel_1; - byte waveform_1; - byte flags_2; - byte oplvl_2; - byte atdec_2; - byte sustrel_2; - byte waveform_2; - byte feedback; - byte flags_a; - InstrumentExtra extra_a; - byte flags_b; - InstrumentExtra extra_b; - byte duration; -}; - -struct Part { - int _slot; - SoundDriver *_drv; - Part *_next, *_prev; - MidiChannel *_mc; - Player *_player; - int16 _pitchbend; - byte _pitchbend_factor; - int8 _transpose,_transpose_eff; - byte _vol,_vol_eff; - int8 _detune,_detune_eff; - int8 _pan,_pan_eff; - bool _on; - byte _modwheel; - bool _pedal; - byte _program; - int8 _pri; - byte _pri_eff; - byte _chan; - byte _effect_level; - byte _chorus; - byte _percussion; - byte _bank; - - void key_on(byte note, byte velocity); - void key_off(byte note); - void set_param(byte param, int value); - void init(SoundDriver *_driver); - void setup(Player *player); - void uninit(); - void off(); - void silence(); - void set_instrument(uint b); - void set_instrument(Instrument *data); - - void set_transpose(int8 transpose); - void set_vol(uint8 volume); - void set_detune(int8 detune); - void set_pri(int8 pri); - void set_pan(int8 pan); - void set_modwheel(uint value); - void set_pedal(bool value); - void set_pitchbend(int value); - void release_pedal(); - void set_program(byte program); - void set_chorus(uint chorus); - void set_effect_level(uint level); - - int update_actives(uint16 *active); - void set_pitchbend_factor(uint8 value); - void set_onoff(bool on); - void fix_after_load(); - - void update_pris(); - - void changed(byte what); -}; - - -struct MidiChannel { - Part *_part; - MidiChannelAdl *adl() { return (MidiChannelAdl*)this; } - MidiChannelGM *gm() { return (MidiChannelGM*)this; } -}; - -struct MidiChannelAdl : MidiChannel { - MidiChannelAdl *_next,*_prev; - byte _waitforpedal; - byte _note; - byte _channel; - byte _twochan; - byte _vol_1,_vol_2; - int16 _duration; - - Struct10 _s10a; - Struct11 _s11a; - Struct10 _s10b; - Struct11 _s11b; -}; - -struct MidiChannelGM : MidiChannel { - byte _chan; - uint16 _actives[8]; -}; - -struct VolumeFader { - Player *player; - bool active; - byte curvol; - uint16 speed_lo_max,num_steps; - int8 speed_hi; - int8 direction; - int8 speed_lo; - uint16 speed_lo_counter; - - void initialize() { active = false; } - void on_timer(); -}; - -struct HookDatas { - byte _jump,_transpose; - byte _part_onoff[16]; - byte _part_volume[16]; - byte _part_program[16]; - byte _part_transpose[16]; - - int query_param(int param, byte chan); - int set(byte cls, byte value, byte chan); -}; - -struct Player { - SoundEngine *_se; - - Part *_parts; - bool _active; - bool _scanning; - int _id; - byte _priority; - byte _volume; - int8 _pan; - int8 _transpose; - int8 _detune; - uint _vol_chan; - byte _vol_eff; - - uint _song_index; - uint _track_index; - uint _timer_counter; - uint _loop_to_beat; - uint _loop_from_beat; - uint _loop_counter; - uint _loop_to_tick; - uint _loop_from_tick; - uint32 _tempo; - uint32 _tempo_eff; /* NoSave */ - uint32 _cur_pos; - uint32 _next_pos; - uint32 _song_offset; - uint32 _timer_speed; /* NoSave */ - uint _tick_index; - uint _beat_index; - uint _ticks_per_beat; - byte _speed; /* NoSave */ - bool _abort; - - HookDatas _hook; - - /* Player part */ - void hook_clear(); - void clear(); - bool start_sound(int sound); - void uninit_parts(); - byte *parse_midi(byte *s); - void key_off(uint8 chan, byte data); - void key_on(uint8 chan, byte data, byte velocity); - void part_set_transpose(uint8 chan, byte relative, int8 b); - void parse_sysex(byte *p, uint len); - void maybe_jump(byte *data); - void maybe_set_transpose(byte *data); - void maybe_part_onoff(byte *data); - void maybe_set_volume(byte *data); - void maybe_set_program(byte *data); - void maybe_set_transpose_part(byte *data); - uint update_actives(); - Part *get_part(uint8 part); - void turn_off_pedals(); - int set_vol(byte vol); - int get_param(int param, byte chan); - int query_part_param(int param, byte chan); - int set_transpose(byte relative, int b); - void set_priority(int pri); - void set_pan(int pan); - void set_detune(int detune); - void turn_off_parts(); - void play_active_notes(); - void cancel_volume_fade(); - - static void decode_sysex_bytes(byte *src, byte *dst, int len); - - void clear_active_note(int chan, byte note); - void set_active_note(int chan, byte note); - void clear_active_notes(); - - /* Sequencer part */ - bool set_loop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick); - void clear_loop(); - void set_speed(byte speed); - bool jump(uint track, uint beat, uint tick); - void uninit_seq(); - void set_tempo(uint32 data); - int start_seq_sound(int sound); - void find_sustaining_notes(byte *a, byte *b, uint32 l); - int scan(uint totrack, uint tobeat, uint totick); - int query_param(int param); - - int fade_vol(byte vol, int time); - void sequencer_timer(); -}; - - -struct SustainingNotes { - SustainingNotes *next; - SustainingNotes *prev; - Player *player; - byte note,chan; - uint32 off_pos; - uint32 pos; - uint16 counter; -}; - -struct CommandQueue { - uint16 array[8]; -}; - -struct IsNoteCmdData { - byte chan; - byte note; - byte vel; -}; - -struct SoundDriver { - enum { - pcMod = 1, - pcVolume = 2, - pcPedal = 4, - pcModwheel = 8, - pcPan = 16, - pcEffectLevel = 32, - pcProgram = 64, - pcChorus = 128, - pcAll = 255, - }; - - virtual void on_timer() = 0; - virtual uint32 get_base_tempo() = 0; - virtual byte get_hardware_type() = 0; - virtual void init(SoundEngine *eng, OSystem *syst) = 0; - virtual void update_pris() = 0; - virtual void set_instrument(uint slot, byte *instr) = 0; - virtual void part_set_instrument(Part *part, Instrument *instr) = 0; - virtual void part_key_on(Part *part, byte note, byte velocity) = 0; - virtual void part_key_off(Part *part, byte note) = 0; - virtual void part_off(Part *part) = 0; - virtual void part_changed(Part *part,byte what) = 0; - virtual void part_set_param(Part *part, byte param, int value) = 0; - virtual int part_update_active(Part *part,uint16 *active) = 0; - virtual void generate_samples(int16 *buf, int len) = 0; -}; - -struct AdlibSoundDriver : SoundDriver { -private: - FM_OPL *_opl; - byte *_adlib_reg_cache; - SoundEngine *_se; - - int _adlib_timer_counter; - - uint16 channel_table_2[9]; - int _midichan_index; - int _next_tick; - uint16 curnote_table[9]; - MidiChannelAdl _midi_channels[9]; - - Instrument _part_instr[32]; - Instrument _glob_instr[32]; - - void adlib_key_off(int chan); - void adlib_note_on(int chan, byte note, int mod); - void adlib_note_on_ex(int chan, byte note, int mod); - int adlib_read_param(int chan, byte data); - void adlib_setup_channel(int chan, Instrument *instr, byte vol_1, byte vol_2); - byte adlib_read(byte port) { return _adlib_reg_cache[port]; } - void adlib_set_param(int channel, byte param, int value); - void adlib_key_onoff(int channel); - void adlib_write(byte port, byte value); - void adlib_playnote(int channel, int note); - - MidiChannelAdl *allocate_midichan(byte pri); - - void reset_tick(); - void mc_off(MidiChannel *mc); - - static void link_mc(Part *part, MidiChannelAdl *mc); - static void mc_inc_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11); - static void mc_init_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11, byte flags, InstrumentExtra *ie); - static void struct10_init(Struct10 *s10, InstrumentExtra *ie); - static byte struct10_ontimer(Struct10 *s10, Struct11 *s11); - static void struct10_setup(Struct10 *s10); - static int random_nr(int a); - void mc_key_on(MidiChannel *mc, byte note, byte velocity); - -public: - void uninit(); - void init(SoundEngine *eng, OSystem *syst); - void update_pris() { } - void generate_samples(int16 *buf, int len); - void on_timer(); - void set_instrument(uint slot, byte *instr); - void part_set_instrument(Part *part, Instrument *instr); - void part_key_on(Part *part, byte note, byte velocity); - void part_key_off(Part *part, byte note); - void part_set_param(Part *part, byte param, int value); - void part_changed(Part *part,byte what); - void part_off(Part *part); - int part_update_active(Part *part,uint16 *active); - void adjust_priorities() {} - - uint32 get_base_tempo() { -#ifdef _WIN32_WCE - return 0x1F0000 * 2; // Sampled down to 11 kHz -#else //_WIN32_WCE - return 0x1924E0; -#endif //_WIN32_WCE - } - - byte get_hardware_type() { return 1; } -}; - -#if 0 -struct MidiDriver { - bool MidiInitialized; - int DeviceType; - int SeqDevice; - void *_mo; /* midi out */ - - void midiInit(); - void midiInitTimidity(); - void midiInitSeq(); - void midiInitWindows(); - void midiInitNull(); - void midiInitQuicktime(); - - void MidiOut(int b); - void MidiOutSeq(void *a, int b); - void MidiOutWindows(void *a, int b); - void MidiOutQuicktime(void *a, int b); - void MidiOutMorphOS(void *a, int b); - - int connect_to_timidity(int port); - int open_sequencer_device(); -}; -#endif - -struct MidiSoundDriver : SoundDriver { - SoundEngine *_se; - OSystem *_system; - - MidiChannelGM _midi_channels[9]; - - int16 _midi_pitchbend_last[16]; - uint8 _midi_volume_last[16]; - bool _midi_pedal_last[16]; - byte _midi_modwheel_last[16]; - byte _midi_effectlevel_last[16]; - byte _midi_chorus_last[16]; - int8 _midi_pan_last[16]; - - MidiDriver *_md; - void midiPitchBend(byte chan, int16 pitchbend); - void midiVolume(byte chan, byte volume); - void midiPedal(byte chan, bool pedal); - void midiModWheel(byte chan, byte modwheel); - void midiEffectLevel(byte chan, byte level); - void midiChorus(byte chan, byte chorus); - void midiControl0(byte chan, byte value); - void midiProgram(byte chan, byte program); - void midiPan(byte chan, int8 pan); - void midiNoteOn(byte chan, byte note, byte velocity); - void midiNoteOff(byte chan, byte note); - void midiSilence(byte chan); - void midiInit(); - -public: - void uninit(); - void init(SoundEngine *eng, OSystem *os); - void update_pris(); - void part_off(Part *part); - int part_update_active(Part *part,uint16 *active); - - void generate_samples(int16 *buf, int len) {} - void on_timer() {} - void set_instrument(uint slot, byte *instr) {} - void part_set_instrument(Part *part, Instrument *instr) {} - void part_set_param(Part *part, byte param, int value) {} - void part_key_on(Part *part, byte note, byte velocity); - void part_key_off(Part *part, byte note); - void part_changed(Part *part,byte what); - void midiSetDriver(MidiDriver *driver); - - static int midi_driver_thread(void *param); - - uint32 get_base_tempo() { return 0x400000; } - byte get_hardware_type() { return 5; } -}; - -struct SoundEngine { -friend struct Player; -private: - SoundDriver *_driver; - - byte **_base_sounds; - - Scumm *_s; - - byte _locked; - byte _hardware_type; - - bool _paused; - bool _active_volume_faders; - bool _initialized; - byte _volume_fader_counter; - - uint _queue_end, _queue_pos, _queue_sound; - byte _queue_adding; - - SustainingNotes *_sustain_notes_used; - SustainingNotes *_sustain_notes_free; - SustainingNotes *_sustain_notes_head; - - byte _queue_marker; - byte _queue_cleared; - byte _master_volume; - byte _music_volume; /* Global music volume. Percantage */ - - uint16 _trigger_count; - - uint16 _channel_volume[8]; - uint16 _channel_volume_eff[8]; /* NoSave */ - uint16 _volchan_table[8]; - - Player _players[8]; - SustainingNotes _sustaining_notes[24]; - VolumeFader _volume_fader[8]; - Part _parts[32]; - - uint16 _active_notes[128]; - CommandQueue _cmd_queue[64]; - - byte *findTag(int sound, char *tag, int index); - int get_queue_sound_status(int sound); - Player *allocate_player(byte priority); - void handle_marker(uint id, byte data); - int get_channel_volume(uint a); - void init_players(); - void init_parts(); - void init_volume_fader(); - void init_sustaining_notes(); - void init_queue(); - - void sequencer_timers(); - void expire_sustain_notes(); - void expire_volume_faders(); - - Part *allocate_part(byte pri); - - int enqueue_command(int a, int b, int c, int d, int e, int f, int g); - int enqueue_trigger(int sound, int marker); - int query_queue(int param); - Player *get_player_byid(int id); - - int get_volchan_entry(uint a); - int set_volchan_entry(uint a, uint b); - int set_channel_volume(uint chan, uint vol); - void update_volumes(); - void reset_tick(); - VolumeFader *allocate_volume_fader(); - - int set_volchan(int sound, int volchan); - - void fix_parts_after_load(); - void fix_players_after_load(); - - static int saveReference(SoundEngine *me, byte type, void *ref); - static void *loadReference(SoundEngine *me, byte type, int ref); - - void lock(); - void unlock(); - -public: - void on_timer(); - Part *parts_ptr() { return _parts; } - void pause(bool paused); - int initialize(Scumm *scumm, SoundDriver *driver); - int terminate(); - int save_or_load(Serializer *ser); - int set_music_volume(uint vol); - int get_music_volume(); - int set_master_volume(uint vol); - int get_master_volume(); - bool start_sound(int sound); - int stop_sound(int sound); - int stop_all_sounds(); - int get_sound_status(int sound); - int32 do_command(int a, int b, int c, int d, int e, int f, int g, int h); - int clear_queue(); - void setBase(byte **base) { _base_sounds = base; } - - SoundDriver *driver() { return _driver; } - bool _mt32emulate; -}; - - -#endif \ No newline at end of file diff --git a/sound/adlib.cpp b/sound/adlib.cpp deleted file mode 100644 index 9700d992551..00000000000 --- a/sound/adlib.cpp +++ /dev/null @@ -1,989 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001/2002 The ScummVM project - * - * 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. - * - * $Header$ - */ - -#include "stdafx.h" -#include "scumm.h" -#include "fmopl.h" - - -static byte lookup_table[64][32]; -const byte volume_table[] = { - 0, 4, 7, 11, - 13, 16, 18, 20, - 22, 24, 26, 27, - 29, 30, 31, 33, - 34, 35, 36, 37, - 38, 39, 40, 41, - 42, 43, 44, 44, - 45, 46, 47, 47, - 48, 49, 49, 50, - 51, 51, 52, 53, - 53, 54, 54, 55, - 55, 56, 56, 57, - 57, 58, 58, 59, - 59, 60, 60, 60, - 61, 61, 62, 62, - 62, 63, 63, 63 -}; - -int lookup_volume(int a, int b) -{ - if (b == 0) - return 0; - - if (b == 31) - return a; - - if (a < -63 || a > 63) { - return b * (a + 1) >> 5; - } - - if (b < 0) { - if (a < 0) { - return lookup_table[-a][-b]; - } else { - return -lookup_table[a][-b]; - } - } else { - if (a < 0) { - return -lookup_table[-a][b]; - } else { - return lookup_table[a][b]; - } - } -} - -void create_lookup_table() -{ - int i, j; - int sum; - - for (i = 0; i < 64; i++) { - sum = i; - for (j = 0; j < 32; j++) { - lookup_table[i][j] = sum >> 5; - sum += i; - } - } - for (i = 0; i < 64; i++) - lookup_table[i][0] = 0; -} - -MidiChannelAdl *AdlibSoundDriver::allocate_midichan(byte pri) -{ - MidiChannelAdl *ac, *best = NULL; - int i; - - for (i = 0; i < 9; i++) { - if (++_midichan_index >= 9) - _midichan_index = 0; - ac = &_midi_channels[_midichan_index]; - if (!ac->_part) - return ac; - if (!ac->_next) { - if (ac->_part->_pri_eff <= pri) { - pri = ac->_part->_pri_eff; - best = ac; - } - } - } - - if (best) - mc_off(best); - else; //debug(1, "Denying adlib channel request"); - return best; -} - -void AdlibSoundDriver::init(SoundEngine *eng, OSystem *syst) -{ - int i; - MidiChannelAdl *mc; - - _se = eng; - - for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) { - mc->_channel = i; - mc->_s11a.s10 = &mc->_s10b; - mc->_s11b.s10 = &mc->_s10a; - } - - _adlib_reg_cache = (byte *)calloc(256, 1); - -#ifdef _WIN32_WCE // Poor WIN32 won't handle 22050 well ! - _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, 11025); -#else - _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, 22050); -#endif - adlib_write(1, 0x20); - adlib_write(8, 0x40); - adlib_write(0xBD, 0x00); - create_lookup_table(); -} - -void AdlibSoundDriver::adlib_write(byte port, byte value) -{ - if (_adlib_reg_cache[port] == value) - return; - _adlib_reg_cache[port] = value; - - OPLWriteReg(_opl, port, value); -} - -void AdlibSoundDriver::adlib_key_off(int chan) -{ - byte port = chan + 0xB0; - adlib_write(port, adlib_read(port) & ~0x20); -} - -struct AdlibSetParams { - byte a, b, c, d; -}; - -static const byte channel_mappings[9] = { - 0, 1, 2, 8, - 9, 10, 16, 17, - 18 -}; - -static const byte channel_mappings_2[9] = { - 3, 4, 5, 11, - 12, 13, 19, 20, - 21 -}; - -static const AdlibSetParams adlib_setparam_table[] = { - {0x40, 0, 63, 63}, /* level */ - {0xE0, 2, 0, 0}, /* unused */ - {0x40, 6, 192, 0}, /* level key scaling */ - {0x20, 0, 15, 0}, /* modulator frequency multiple */ - {0x60, 4, 240, 15}, /* attack rate */ - {0x60, 0, 15, 15}, /* decay rate */ - {0x80, 4, 240, 15}, /* sustain level */ - {0x80, 0, 15, 15}, /* release rate */ - {0xE0, 0, 3, 0}, /* waveform select */ - {0x20, 7, 128, 0}, /* amp mod */ - {0x20, 6, 64, 0}, /* vib */ - {0x20, 5, 32, 0}, /* eg typ */ - {0x20, 4, 16, 0}, /* ksr */ - {0xC0, 0, 1, 0}, /* decay alg */ - {0xC0, 1, 14, 0} /* feedback */ -}; - -void AdlibSoundDriver::adlib_set_param(int channel, byte param, int value) -{ - const AdlibSetParams *as; - byte port; - - assert(channel >= 0 && channel < 9); - - if (param <= 12) { - port = channel_mappings_2[channel]; - } else if (param <= 25) { - param -= 13; - port = channel_mappings[channel]; - } else if (param <= 27) { - param -= 13; - port = channel; - } else if (param == 28 || param == 29) { - if (param == 28) - value -= 15; - else - value -= 383; - value <<= 4; - channel_table_2[channel] = value; - adlib_playnote(channel, curnote_table[channel] + value); - return; - } else { - return; - } - - as = &adlib_setparam_table[param]; - if (as->d) - value = as->d - value; - port += as->a; - adlib_write(port, (adlib_read(port) & ~as->c) | (((byte)value) << as->b)); -} - -static const byte octave_numbers[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7 -}; - -static const byte note_numbers[] = { - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 3, 4, 5, 6, 7, 8, 9, 10 -}; - -static const byte note_to_f_num[] = { - 90, 91, 92, 92, 93, 94, 94, 95, - 96, 96, 97, 98, 98, 99, 100, 101, - 101, 102, 103, 104, 104, 105, 106, 107, - 107, 108, 109, 110, 111, 111, 112, 113, - 114, 115, 115, 116, 117, 118, 119, 120, - 121, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, - 143, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 157, 158, 159, 160, - 161, 162, 163, 165, 166, 167, 168, 169, - 171, 172, 173, 174, 176, 177, 178, 180, - 181, 182, 184, 185, 186, 188, 189, 190, - 192, 193, 194, 196, 197, 199, 200, 202, - 203, 205, 206, 208, 209, 211, 212, 214, - 215, 217, 218, 220, 222, 223, 225, 226, - 228, 230, 231, 233, 235, 236, 238, 240, - 242, 243, 245, 247, 249, 251, 252, 254, -}; - -void AdlibSoundDriver::adlib_playnote(int channel, int note) -{ - byte old, oct, notex; - int note2; - int i; - - note2 = (note >> 7) - 4; - - oct = octave_numbers[note2] << 2; - notex = note_numbers[note2]; - - old = adlib_read(channel + 0xB0); - if (old & 0x20) { - old &= ~0x20; - if (oct > old) { - if (notex < 6) { - notex += 12; - oct -= 4; - } - } else if (oct < old) { - if (notex > 11) { - notex -= 12; - oct += 4; - } - } - } - - i = (notex << 3) + ((note >> 4) & 0x7); - adlib_write(channel + 0xA0, note_to_f_num[i]); - adlib_write(channel + 0xB0, oct | 0x20); -} - -void AdlibSoundDriver::adlib_note_on(int chan, byte note, int mod) -{ - int code; - assert(chan >= 0 && chan < 9); - code = (note << 7) + mod; - curnote_table[chan] = code; - adlib_playnote(chan, channel_table_2[chan] + code); -} - -void AdlibSoundDriver::adlib_note_on_ex(int chan, byte note, int mod) -{ - int code; - assert(chan >= 0 && chan < 9); - code = (note << 7) + mod; - curnote_table[chan] = code; - channel_table_2[chan] = 0; - adlib_playnote(chan, code); -} - -void AdlibSoundDriver::adlib_key_onoff(int channel) -{ - byte val; - byte port = channel + 0xB0; - assert(channel >= 0 && channel < 9); - - val = adlib_read(port); - adlib_write(port, val & ~0x20); - adlib_write(port, val | 0x20); -} - -void AdlibSoundDriver::adlib_setup_channel(int chan, Instrument * instr, - byte vol_1, byte vol_2) -{ - byte port; - - assert(chan >= 0 && chan < 9); - - port = channel_mappings[chan]; - adlib_write(port + 0x20, instr->flags_1); - adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1); - adlib_write(port + 0x60, ~instr->atdec_1); - adlib_write(port + 0x80, ~instr->sustrel_1); - adlib_write(port + 0xE0, instr->waveform_1); - - port = channel_mappings_2[chan]; - adlib_write(port + 0x20, instr->flags_2); - adlib_write(port + 0x40, (instr->oplvl_2 | 0x3F) - vol_2); - adlib_write(port + 0x60, ~instr->atdec_2); - adlib_write(port + 0x80, ~instr->sustrel_2); - adlib_write(port + 0xE0, instr->waveform_2); - - adlib_write((byte)chan + 0xC0, instr->feedback); -} - -int AdlibSoundDriver::adlib_read_param(int chan, byte param) -{ - const AdlibSetParams *as; - byte val; - byte port; - - assert(chan >= 0 && chan < 9); - - if (param <= 12) { - port = channel_mappings_2[chan]; - } else if (param <= 25) { - param -= 13; - port = channel_mappings[chan]; - } else if (param <= 27) { - param -= 13; - port = chan; - } else if (param == 28) { - return 0xF; - } else if (param == 29) { - return 0x17F; - } else { - return 0; - } - - as = &adlib_setparam_table[param]; - val = adlib_read(port + as->a); - val &= as->c; - val >>= as->b; - if (as->d) - val = as->d - val; - - return val; -} - -void AdlibSoundDriver::generate_samples(int16 * data, int len) -{ - int step; - - if (!_opl) { - memset(data, 0, len * sizeof(int16)); - return; - } - - do { - step = len; - if (step > _next_tick) - step = _next_tick; - YM3812UpdateOne(_opl, data, step); - - if (!(_next_tick -= step)) { - _se->on_timer(); - reset_tick(); - } - data += step; - } while (len -= step); -} - -void AdlibSoundDriver::reset_tick() -{ - _next_tick = 88; -} - -void AdlibSoundDriver::on_timer() -{ - MidiChannelAdl *mc; - int i; - - _adlib_timer_counter += 0xD69; - while (_adlib_timer_counter >= 0x411B) { - _adlib_timer_counter -= 0x411B; - mc = _midi_channels; - for (i = 0; i != ARRAYSIZE(_midi_channels); i++, mc++) { - if (!mc->_part) - continue; - if (mc->_duration && (mc->_duration -= 0x11) <= 0) { - mc_off(mc); - return; - } - if (mc->_s10a.active) { - mc_inc_stuff(mc, &mc->_s10a, &mc->_s11a); - } - if (mc->_s10b.active) { - mc_inc_stuff(mc, &mc->_s10b, &mc->_s11b); - } - } - } -} - -const byte param_table_1[16] = { - 29, 28, 27, 0, - 3, 4, 7, 8, - 13, 16, 17, 20, - 21, 30, 31, 0 -}; - -const uint16 param_table_2[16] = { - 0x2FF, 0x1F, 0x7, 0x3F, - 0x0F, 0x0F, 0x0F, 0x3, - 0x3F, 0x0F, 0x0F, 0x0F, - 0x3, 0x3E, 0x1F, 0 -}; - -static const uint16 num_steps_table[] = { - 1, 2, 4, 5, - 6, 7, 8, 9, - 10, 12, 14, 16, - 18, 21, 24, 30, - 36, 50, 64, 82, - 100, 136, 160, 192, - 240, 276, 340, 460, - 600, 860, 1200, 1600 -}; - -int AdlibSoundDriver::random_nr(int a) -{ - static byte _rand_seed = 1; - if (_rand_seed & 1) { - _rand_seed >>= 1; - _rand_seed ^= 0xB8; - } else { - _rand_seed >>= 1; - } - return _rand_seed * a >> 8; -} - -void AdlibSoundDriver::struct10_setup(Struct10 * s10) -{ - int b, c, d, e, f, g, h; - byte t; - - b = s10->unk3; - f = s10->active - 1; - - t = s10->table_a[f]; - e = num_steps_table[lookup_table[t & 0x7F][b]]; - if (t & 0x80) { - e = random_nr(e); - } - if (e == 0) - e++; - - s10->num_steps = s10->speed_lo_max = e; - - if (f != 2) { - c = s10->param; - g = s10->start_value; - t = s10->table_b[f]; - d = lookup_volume(c, (t & 0x7F) - 31); - if (t & 0x80) { - d = random_nr(d); - } - if (d + g > c) { - h = c - g; - } else { - h = d; - if (d + g < 0) - h = -g; - } - h -= s10->cur_val; - } else { - h = 0; - } - - s10->speed_hi = h / e; - if (h < 0) { - h = -h; - s10->direction = -1; - } else { - s10->direction = 1; - } - - s10->speed_lo = h % e; - s10->speed_lo_counter = 0; -} - -byte AdlibSoundDriver::struct10_ontimer(Struct10 * s10, Struct11 * s11) -{ - byte result = 0; - int i; - - if (s10->count && (s10->count -= 17) <= 0) { - s10->active = 0; - return 0; - } - - i = s10->cur_val + s10->speed_hi; - s10->speed_lo_counter += s10->speed_lo; - if (s10->speed_lo_counter >= s10->speed_lo_max) { - s10->speed_lo_counter -= s10->speed_lo_max; - i += s10->direction; - } - if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) { - s10->cur_val = i; - s10->modwheel_last = s10->modwheel; - i = lookup_volume(i, s10->modwheel_last); - if (i != s11->modify_val) { - s11->modify_val = i; - result = 1; - } - } - - if (!--s10->num_steps) { - s10->active++; - if (s10->active > 4) { - if (s10->loop) { - s10->active = 1; - result |= 2; - struct10_setup(s10); - } else { - s10->active = 0; - } - } else { - struct10_setup(s10); - } - } - - return result; -} - -void AdlibSoundDriver::struct10_init(Struct10 * s10, InstrumentExtra * ie) -{ - s10->active = 1; - s10->cur_val = 0; - s10->modwheel_last = 31; - s10->count = ie->a; - if (s10->count) - s10->count *= 63; - s10->table_a[0] = ie->b; - s10->table_a[1] = ie->d; - s10->table_a[2] = ie->f; - s10->table_a[3] = ie->g; - - s10->table_b[0] = ie->c; - s10->table_b[1] = ie->e; - s10->table_b[2] = 0; - s10->table_b[3] = ie->h; - - struct10_setup(s10); -} - -void AdlibSoundDriver::mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, - Struct11 * s11, byte flags, - InstrumentExtra * ie) -{ - Part *part = mc->_part; - - s11->modify_val = 0; - s11->flag0x40 = flags & 0x40; - s10->loop = flags & 0x20; - s11->flag0x10 = flags & 0x10; - s11->param = param_table_1[flags & 0xF]; - s10->param = param_table_2[flags & 0xF]; - s10->unk3 = 31; - if (s11->flag0x40) { - s10->modwheel = part->_modwheel >> 2; - } else { - s10->modwheel = 31; - } - - switch (s11->param) { - case 0: - s10->start_value = mc->_vol_2; - break; - case 13: - s10->start_value = mc->_vol_1; - break; - case 30: - s10->start_value = 31; - s11->s10->modwheel = 0; - break; - case 31: - s10->start_value = 0; - s11->s10->unk3 = 0; - break; - default: - s10->start_value = ((AdlibSoundDriver*)part->_drv)->adlib_read_param(mc->_channel, s11->param); - } - - struct10_init(s10, ie); -} - -void AdlibSoundDriver::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, - Struct11 * s11) -{ - byte code; - Part *part = mc->_part; - - code = struct10_ontimer(s10, s11); - - if (code & 1) { - switch (s11->param) { - case 0: - mc->_vol_2 = s10->start_value + s11->modify_val; - ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 0, - volume_table[lookup_table[mc->_vol_2] - [part->_vol_eff >> 2]]); - break; - case 13: - mc->_vol_1 = s10->start_value + s11->modify_val; - if (mc->_twochan) { - ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 13, - volume_table[lookup_table[mc->_vol_1] - [part->_vol_eff >> 2]]); - } else { - ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 13, mc->_vol_1); - } - break; - case 30: - s11->s10->modwheel = (char)s11->modify_val; - break; - case 31: - s11->s10->unk3 = (char)s11->modify_val; - break; - default: - ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, s11->param, - s10->start_value + s11->modify_val); - break; - } - } - - if (code & 2 && s11->flag0x10) - ((AdlibSoundDriver*)part->_drv)->adlib_key_onoff(mc->_channel); -} - -void AdlibSoundDriver::part_changed(Part *part, byte what) -{ - MidiChannelAdl *mc; - - if (what & pcProgram) { - if (part->_program < 32) { - part_set_instrument(part, &_glob_instr[part->_program]); - } - } - - if (what & pcMod) { - for (mc = part->_mc->adl(); mc; mc = mc->_next) { - adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, - part->_pitchbend + part->_detune_eff); - } - } - - if (what & pcVolume) { - for (mc = part->_mc->adl(); mc; mc = mc->_next) { - adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2] - [part->_vol_eff >> 2]]); - if (mc->_twochan) { - adlib_set_param(mc->_channel, 13, - volume_table[lookup_table[mc->_vol_1] - [part->_vol_eff >> 2]]); - } - } - } - - if (what & pcPedal) { - if (!part->_pedal) { - for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { - if (mc->_waitforpedal) - mc_off(mc); - } - } - } - - if (what & pcModwheel) { - for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { - if (mc->_s10a.active && mc->_s11a.flag0x40) - mc->_s10a.modwheel = part->_modwheel >> 2; - if (mc->_s10b.active && mc->_s11b.flag0x40) - mc->_s10b.modwheel = part->_modwheel >> 2; - } - } -} - -void AdlibSoundDriver::mc_key_on(MidiChannel * mc2, byte note, byte velocity) -{ - MidiChannelAdl *mc = (MidiChannelAdl *)mc2; - Part *part = mc->_part; - Instrument *instr = &_part_instr[part->_slot]; - int c; - byte vol_1, vol_2; - - mc->_twochan = instr->feedback & 1; - mc->_note = note; - mc->_waitforpedal = false; - mc->_duration = instr->duration; - if (mc->_duration != 0) - mc->_duration *= 63; - - vol_1 = - (instr->oplvl_1 & 0x3F) + - lookup_table[velocity >> 1][instr->waveform_1 >> 2]; - if (vol_1 > 0x3F) - vol_1 = 0x3F; - mc->_vol_1 = vol_1; - - vol_2 = - (instr->oplvl_2 & 0x3F) + - lookup_table[velocity >> 1][instr->waveform_2 >> 2]; - if (vol_2 > 0x3F) - vol_2 = 0x3F; - mc->_vol_2 = vol_2; - - c = part->_vol_eff >> 2; - - vol_2 = volume_table[lookup_table[vol_2][c]]; - if (mc->_twochan) - vol_1 = volume_table[lookup_table[vol_1][c]]; - - adlib_setup_channel(mc->_channel, instr, vol_1, vol_2); - adlib_note_on_ex(mc->_channel, part->_transpose_eff + note, - part->_detune_eff + part->_pitchbend); - - if (instr->flags_a & 0x80) { - mc_init_stuff(mc, &mc->_s10a, &mc->_s11a, instr->flags_a, - &instr->extra_a); - } else { - mc->_s10a.active = 0; - } - - if (instr->flags_b & 0x80) { - mc_init_stuff(mc, &mc->_s10b, &mc->_s11b, instr->flags_b, - &instr->extra_b); - } else { - mc->_s10b.active = 0; - } -} - -void AdlibSoundDriver::set_instrument(uint slot, byte *data) -{ - if (slot < 32) { - memcpy(&_glob_instr[slot], data, sizeof(Instrument)); - } -} - - -void AdlibSoundDriver::link_mc(Part *part, MidiChannelAdl *mc) -{ - mc->_part = part; - mc->_next = (MidiChannelAdl *)part->_mc; - part->_mc = mc; - mc->_prev = NULL; - - if (mc->_next) - mc->_next->_prev = mc; -} - -void AdlibSoundDriver::part_key_on(Part *part, byte note, byte velocity) -{ - MidiChannelAdl *mc; - - mc = allocate_midichan(part->_pri_eff); - if (!mc) - return; - - link_mc(part, mc); - mc_key_on(mc, note, velocity); -} - -void AdlibSoundDriver::part_key_off(Part *part, byte note) -{ - MidiChannelAdl *mc; - - for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { - if (mc->_note == note) { - if (part->_pedal) - mc->_waitforpedal = true; - else - mc_off(mc); - } - } -} - -struct AdlibInstrSetParams { - byte param; - byte shl; - byte mask; -}; - -#define MKLINE(_a_,_b_,_c_) { (int)&((Instrument*)0)->_a_, _b_, ((1<<(_c_))-1)<<(_b_) } -static const AdlibInstrSetParams adlib_instr_params[69] = { - MKLINE(oplvl_2, 0, 6), - MKLINE(waveform_2, 2, 5), - MKLINE(oplvl_2, 6, 2), - MKLINE(flags_2, 0, 4), - MKLINE(atdec_2, 4, 4), - MKLINE(atdec_2, 0, 4), - MKLINE(sustrel_2, 4, 4), - MKLINE(sustrel_2, 0, 4), - MKLINE(waveform_2, 0, 2), - MKLINE(flags_2, 7, 1), - MKLINE(flags_2, 6, 1), - MKLINE(flags_2, 5, 1), - MKLINE(flags_2, 4, 1), - - MKLINE(oplvl_1, 0, 6), - MKLINE(waveform_1, 2, 5), - MKLINE(oplvl_1, 6, 2), - MKLINE(flags_1, 0, 4), - MKLINE(atdec_1, 4, 4), - MKLINE(atdec_1, 0, 4), - MKLINE(sustrel_1, 4, 4), - MKLINE(sustrel_1, 0, 4), - MKLINE(waveform_1, 0, 2), - MKLINE(flags_1, 7, 1), - MKLINE(flags_1, 6, 1), - MKLINE(flags_1, 5, 1), - MKLINE(flags_1, 4, 1), - - MKLINE(feedback, 0, 1), - MKLINE(feedback, 1, 3), - - MKLINE(flags_a, 7, 1), - MKLINE(flags_a, 6, 1), - MKLINE(flags_a, 5, 1), - MKLINE(flags_a, 4, 1), - MKLINE(flags_a, 0, 4), - MKLINE(extra_a.a, 0, 8), - MKLINE(extra_a.b, 0, 7), - MKLINE(extra_a.c, 0, 7), - MKLINE(extra_a.d, 0, 7), - MKLINE(extra_a.e, 0, 7), - MKLINE(extra_a.f, 0, 7), - MKLINE(extra_a.g, 0, 7), - MKLINE(extra_a.h, 0, 7), - MKLINE(extra_a.b, 7, 1), - MKLINE(extra_a.c, 7, 1), - MKLINE(extra_a.d, 7, 1), - MKLINE(extra_a.e, 7, 1), - MKLINE(extra_a.f, 7, 1), - MKLINE(extra_a.g, 7, 1), - MKLINE(extra_a.h, 7, 1), - - MKLINE(flags_b, 7, 1), - MKLINE(flags_b, 6, 1), - MKLINE(flags_b, 5, 1), - MKLINE(flags_b, 4, 1), - MKLINE(flags_b, 0, 4), - MKLINE(extra_b.a, 0, 8), - MKLINE(extra_b.b, 0, 7), - MKLINE(extra_b.c, 0, 7), - MKLINE(extra_b.d, 0, 7), - MKLINE(extra_b.e, 0, 7), - MKLINE(extra_b.f, 0, 7), - MKLINE(extra_b.g, 0, 7), - MKLINE(extra_b.h, 0, 7), - MKLINE(extra_b.b, 7, 1), - MKLINE(extra_b.c, 7, 1), - MKLINE(extra_b.d, 7, 1), - MKLINE(extra_b.e, 7, 1), - MKLINE(extra_b.f, 7, 1), - MKLINE(extra_b.g, 7, 1), - MKLINE(extra_b.h, 7, 1), - - MKLINE(duration, 0, 8), -}; -#undef MKLINE - -void AdlibSoundDriver::part_set_param(Part *part, byte param, int value) -{ - const AdlibInstrSetParams *sp = &adlib_instr_params[param]; - byte *p = (byte *)&_part_instr[part->_slot] + sp->param; - *p = (*p & ~sp->mask) | (value << sp->shl); - - if (param < 28) { - MidiChannelAdl *mc; - - for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { - adlib_set_param(mc->_channel, param, value); - } - } -} - -void AdlibSoundDriver::part_off(Part *part) -{ - MidiChannelAdl *mc = (MidiChannelAdl *)part->_mc; - part->_mc = NULL; - for (; mc; mc = mc->_next) { - mc_off(mc); - } -} - -void AdlibSoundDriver::mc_off(MidiChannel * mc2) -{ - MidiChannelAdl *mc = (MidiChannelAdl *)mc2, *tmp; - - adlib_key_off(mc->_channel); - - tmp = mc->_prev; - - if (mc->_next) - mc->_next->_prev = tmp; - if (tmp) - tmp->_next = mc->_next; - else - mc->_part->_mc = mc->_next; - mc->_part = NULL; -} - -void AdlibSoundDriver::part_set_instrument(Part *part, Instrument * instr) -{ - Instrument *i = &_part_instr[part->_slot]; - memcpy(i, instr, sizeof(Instrument)); -} - -int AdlibSoundDriver::part_update_active(Part *part, uint16 *active) -{ - uint16 bits; - int count = 0; - MidiChannelAdl *mc; - - bits = 1 << part->_chan; - - for (mc = part->_mc->adl(); mc; mc = mc->_next) { - if (!(active[mc->_note] & bits)) { - active[mc->_note] |= bits; - count++; - } - } - return count; -} - diff --git a/sound/gmidi.cpp b/sound/gmidi.cpp deleted file mode 100644 index ecd4e560c15..00000000000 --- a/sound/gmidi.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001/2002 The ScummVM project - * - * 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. - * - * $Header$ - */ - -#include "stdafx.h" -#include "scumm.h" -#include "gmidi.h" - -void MidiSoundDriver::midiSetDriver(MidiDriver *driver) -{ - _md = driver; - - int result = _md->open(MidiDriver::MO_SIMPLE); - if (result) - error("MidiSoundDriver::error = %s", MidiDriver::get_error_name(result)); -} - -/****************** Common midi code (SCUMM specific) *****************/ -void MidiSoundDriver::midiPitchBend(byte chan, int16 pitchbend) -{ - uint16 tmp; - - if (_midi_pitchbend_last[chan] != pitchbend) { - _midi_pitchbend_last[chan] = pitchbend; - tmp = (pitchbend << 2) + 0x2000; - _md->send(((tmp >> 7) & 0x7F) << 16 | (tmp & 0x7F) << 8 | 0xE0 | chan); - } -} - -void MidiSoundDriver::midiVolume(byte chan, byte volume) -{ - if (_midi_volume_last[chan] != volume) { - _midi_volume_last[chan] = volume; - _md->send(volume << 16 | 7 << 8 | 0xB0 | chan); - } -} -void MidiSoundDriver::midiPedal(byte chan, bool pedal) -{ - if (_midi_pedal_last[chan] != pedal) { - _midi_pedal_last[chan] = pedal; - _md->send(pedal << 16 | 64 << 8 | 0xB0 | chan); - } -} - -void MidiSoundDriver::midiModWheel(byte chan, byte modwheel) -{ - if (_midi_modwheel_last[chan] != modwheel) { - _midi_modwheel_last[chan] = modwheel; - _md->send(modwheel << 16 | 1 << 8 | 0xB0 | chan); - } -} - -void MidiSoundDriver::midiEffectLevel(byte chan, byte level) -{ - if (_midi_effectlevel_last[chan] != level) { - _midi_effectlevel_last[chan] = level; - _md->send(level << 16 | 91 << 8 | 0xB0 | chan); - } -} - -void MidiSoundDriver::midiChorus(byte chan, byte chorus) -{ - if (_midi_chorus_last[chan] != chorus) { - _midi_chorus_last[chan] = chorus; - _md->send(chorus << 16 | 93 << 8 | 0xB0 | chan); - } -} - -void MidiSoundDriver::midiControl0(byte chan, byte value) -{ - _md->send(value << 16 | 0 << 8 | 0xB0 | chan); -} - -void MidiSoundDriver::midiProgram(byte chan, byte program) -{ - if ((chan + 1) != 10) { /* Ignore percussion prededed by patch change */ - if (_se->_mt32emulate) - program = mt32_to_gmidi[program]; - - _md->send(program << 8 | 0xC0 | chan); - } -} - -void MidiSoundDriver::midiPan(byte chan, int8 pan) -{ - if (_midi_pan_last[chan] != pan) { - _midi_pan_last[chan] = pan; - _md->send(((pan - 64) & 0x7F) << 16 | 10 << 8 | 0xB0 | chan); - } -} - -void MidiSoundDriver::midiNoteOn(byte chan, byte note, byte velocity) -{ - _md->send(velocity << 16 | note << 8 | 0x90 | chan); -} - -void MidiSoundDriver::midiNoteOff(byte chan, byte note) -{ - _md->send(note << 8 | 0x80 | chan); -} - -void MidiSoundDriver::midiSilence(byte chan) -{ - _md->send((64 << 8) | 0xB0 | chan); - _md->send((123 << 8) | 0xB0 | chan); -} - - -void MidiSoundDriver::part_key_on(Part *part, byte note, byte velocity) -{ - MidiChannelGM *mc = part->_mc->gm(); - - if (mc) { - mc->_actives[note >> 4] |= (1 << (note & 0xF)); - midiNoteOn(mc->_chan, note, velocity); - } else if (part->_percussion) { - midiVolume(SPECIAL_CHANNEL, part->_vol_eff); - midiProgram(SPECIAL_CHANNEL, part->_bank); - midiNoteOn(SPECIAL_CHANNEL, note, velocity); - } -} - -void MidiSoundDriver::part_key_off(Part *part, byte note) -{ - MidiChannelGM *mc = part->_mc->gm(); - - if (mc) { - mc->_actives[note >> 4] &= ~(1 << (note & 0xF)); - midiNoteOff(mc->_chan, note); - } else if (part->_percussion) { - midiNoteOff(SPECIAL_CHANNEL, note); - } -} - -int MidiSoundDriver::midi_driver_thread(void *param) { - MidiSoundDriver *mid = (MidiSoundDriver*) param; - int old_time, cur_time; - - old_time = mid->_system->get_msecs(); - - for(;;) { - mid->_system->delay_msecs(10); - - cur_time = mid->_system->get_msecs(); - while (old_time < cur_time) { - old_time += 10; - mid->_se->on_timer(); - } - } -} - -void MidiSoundDriver::init(SoundEngine *eng, OSystem *syst) -{ - int i; - MidiChannelGM *mc; - - _system = syst; - - /* Install the on_timer thread */ - syst->create_thread(midi_driver_thread, this); - _se = eng; - - for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) - mc->_chan = i; -} - -void MidiSoundDriver::update_pris() -{ - Part *part, *hipart; - int i; - byte hipri, lopri; - MidiChannelGM *mc, *lomc; - - while (true) { - hipri = 0; - hipart = NULL; - for (i = 32, part = _se->parts_ptr(); i; i--, part++) { - if (part->_player && !part->_percussion && part->_on && !part->_mc - && part->_pri_eff >= hipri) { - hipri = part->_pri_eff; - hipart = part; - } - } - - if (!hipart) - return; - - lopri = 255; - lomc = NULL; - for (i = ARRAYSIZE(_midi_channels), mc = _midi_channels;; mc++) { - if (!mc->_part) { - lomc = mc; - break; - } - if (mc->_part->_pri_eff <= lopri) { - lopri = mc->_part->_pri_eff; - lomc = mc; - } - - if (!--i) { - if (lopri >= hipri) - return; - lomc->_part->off(); - break; - } - } - - hipart->_mc = lomc; - lomc->_part = hipart; - hipart->changed(pcAll); - } -} - -int MidiSoundDriver::part_update_active(Part *part, uint16 *active) -{ - int i, j; - uint16 *act, mask, bits; - int count = 0; - - bits = 1 << part->_chan; - - act = part->_mc->gm()->_actives; - - for (i = 8; i; i--) { - mask = *act++; - if (mask) { - for (j = 16; j; j--, mask >>= 1, active++) { - if (mask & 1 && !(*active & bits)) { - *active |= bits; - count++; - } - } - } else { - active += 16; - } - } - return count; -} - -void MidiSoundDriver::part_changed(Part *part, byte what) -{ - MidiChannelGM *mc; - - /* Mark for re-schedule if program changed when in pre-state */ - if (what & pcProgram && part->_percussion) { - part->_percussion = false; - update_pris(); - } - - if (!(mc = part->_mc->gm())) - return; - - if (what & pcMod) - midiPitchBend(mc->_chan, - clamp(part->_pitchbend + part->_detune_eff + - (part->_transpose_eff << 7), -2048, 2047)); - - if (what & pcVolume) - midiVolume(mc->_chan, part->_vol_eff); - - if (what & pcPedal) - midiPedal(mc->_chan, part->_pedal); - - if (what & pcModwheel) - midiModWheel(mc->_chan, part->_modwheel); - - if (what & pcPan) - midiPan(mc->_chan, part->_pan_eff); - - if (what & pcEffectLevel) - midiEffectLevel(mc->_chan, part->_effect_level); - - if (what & pcProgram) { - if (part->_bank) { - midiControl0(mc->_chan, part->_bank); - midiProgram(mc->_chan, part->_program); - midiControl0(mc->_chan, 0); - } else { - midiProgram(mc->_chan, part->_program); - } - } - - if (what & pcChorus) - midiChorus(mc->_chan, part->_effect_level); -} - - -void MidiSoundDriver::part_off(Part *part) -{ - MidiChannelGM *mc = part->_mc->gm(); - if (mc) { - part->_mc = NULL; - mc->_part = NULL; - memset(mc->_actives, 0, sizeof(mc->_actives)); - midiSilence(mc->_chan); - } -} diff --git a/sound/imuse.cpp b/sound/imuse.cpp index b91b8a845ca..5f621466fee 100644 --- a/sound/imuse.cpp +++ b/sound/imuse.cpp @@ -20,8 +20,9 @@ */ #include "stdafx.h" - #include "scumm.h" +#include "fmopl.h" +#include "mididrv.h" int num_mix; @@ -36,7 +37,603 @@ int num_mix; #define MDPG_TAG "MDpg" #define MDHD_TAG "MDhd" -int clamp(int val, int min, int max) +/* Roland to General Midi patch table. Still needs much work. */ +static const byte mt32_to_gmidi[128] = { + 0, 1, 2, 4, 4, 5, 5, 3, 16, 17, 18, 18, 19, + 19, 20, 21, 6, 6, 6, 7, 7, 7, 8, 8, 62, 63, + 62, 63, 38, 39, 38, 39, 88, 89, 52, 113, 97, 96, 91, + 85, 14, 101, 68, 95, 86, 103, 88, 80, 48, 49, 51, 45, + 40, 40, 42, 42, 43, 46, 46, 24, 25, 26, 27, 104, 32, + 33, 34, 39, 36, 37, 38, 35, 79, 73, 72, 72, 74, 75, + 64, 65, 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, + 63, 60, 60, 58, 61, 61, 11, 11, 12, 88, 9, 14, 13, + 12, 107, 111, 77, 78, 78, 76, 121, 47, 117, 127, 115, 118, + 116, 118, 94, 115, 9, 55, 124, 123, 125, 126, 127 +}; + + + +/* Put IMUSE specific classes here, instead of in a .h file + * they will only be used from this file, so it will reduce + * compile time */ + +class IMuse; +class IMuseDriver; + +struct Part; +struct MidiChannelAdl; +struct MidiChannelGM; +struct Instrument; + + +struct HookDatas { + byte _jump,_transpose; + byte _part_onoff[16]; + byte _part_volume[16]; + byte _part_program[16]; + byte _part_transpose[16]; + + int query_param(int param, byte chan); + int set(byte cls, byte value, byte chan); +}; + + +struct Player { + IMuse *_se; + + Part *_parts; + bool _active; + bool _scanning; + int _id; + byte _priority; + byte _volume; + int8 _pan; + int8 _transpose; + int8 _detune; + uint _vol_chan; + byte _vol_eff; + + uint _song_index; + uint _track_index; + uint _timer_counter; + uint _loop_to_beat; + uint _loop_from_beat; + uint _loop_counter; + uint _loop_to_tick; + uint _loop_from_tick; + uint32 _tempo; + uint32 _tempo_eff; /* NoSave */ + uint32 _cur_pos; + uint32 _next_pos; + uint32 _song_offset; + uint32 _timer_speed; /* NoSave */ + uint _tick_index; + uint _beat_index; + uint _ticks_per_beat; + byte _speed; /* NoSave */ + bool _abort; + + HookDatas _hook; + + /* Player part */ + void hook_clear(); + void clear(); + bool start_sound(int sound); + void uninit_parts(); + byte *parse_midi(byte *s); + void key_off(uint8 chan, byte data); + void key_on(uint8 chan, byte data, byte velocity); + void part_set_transpose(uint8 chan, byte relative, int8 b); + void parse_sysex(byte *p, uint len); + void maybe_jump(byte *data); + void maybe_set_transpose(byte *data); + void maybe_part_onoff(byte *data); + void maybe_set_volume(byte *data); + void maybe_set_program(byte *data); + void maybe_set_transpose_part(byte *data); + uint update_actives(); + Part *get_part(uint8 part); + void turn_off_pedals(); + int set_vol(byte vol); + int get_param(int param, byte chan); + int query_part_param(int param, byte chan); + int set_transpose(byte relative, int b); + void set_priority(int pri); + void set_pan(int pan); + void set_detune(int detune); + void turn_off_parts(); + void play_active_notes(); + void cancel_volume_fade(); + + static void decode_sysex_bytes(byte *src, byte *dst, int len); + + void clear_active_note(int chan, byte note); + void set_active_note(int chan, byte note); + void clear_active_notes(); + + /* Sequencer part */ + bool set_loop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick); + void clear_loop(); + void set_speed(byte speed); + bool jump(uint track, uint beat, uint tick); + void uninit_seq(); + void set_tempo(uint32 data); + int start_seq_sound(int sound); + void find_sustaining_notes(byte *a, byte *b, uint32 l); + int scan(uint totrack, uint tobeat, uint totick); + int query_param(int param); + + int fade_vol(byte vol, int time); + void sequencer_timer(); +}; + +struct VolumeFader { + Player *player; + bool active; + byte curvol; + uint16 speed_lo_max,num_steps; + int8 speed_hi; + int8 direction; + int8 speed_lo; + uint16 speed_lo_counter; + + void initialize() { active = false; } + void on_timer(); +}; + +struct SustainingNotes { + SustainingNotes *next; + SustainingNotes *prev; + Player *player; + byte note,chan; + uint32 off_pos; + uint32 pos; + uint16 counter; +}; + +struct CommandQueue { + uint16 array[8]; +}; + + +struct IsNoteCmdData { + byte chan; + byte note; + byte vel; +}; + + + +struct MidiChannel { + Part *_part; + MidiChannelAdl *adl() { return (MidiChannelAdl*)this; } + MidiChannelGM *gm() { return (MidiChannelGM*)this; } +}; + + +struct MidiChannelGM : MidiChannel { + byte _chan; + uint16 _actives[8]; +}; + + +struct Part { + int _slot; + IMuseDriver *_drv; + Part *_next, *_prev; + MidiChannel *_mc; + Player *_player; + int16 _pitchbend; + byte _pitchbend_factor; + int8 _transpose,_transpose_eff; + byte _vol,_vol_eff; + int8 _detune,_detune_eff; + int8 _pan,_pan_eff; + bool _on; + byte _modwheel; + bool _pedal; + byte _program; + int8 _pri; + byte _pri_eff; + byte _chan; + byte _effect_level; + byte _chorus; + byte _percussion; + byte _bank; + + void key_on(byte note, byte velocity); + void key_off(byte note); + void set_param(byte param, int value); + void init(IMuseDriver *_driver); + void setup(Player *player); + void uninit(); + void off(); + void silence(); + void set_instrument(uint b); + void set_instrument(Instrument *data); + + void set_transpose(int8 transpose); + void set_vol(uint8 volume); + void set_detune(int8 detune); + void set_pri(int8 pri); + void set_pan(int8 pan); + void set_modwheel(uint value); + void set_pedal(bool value); + void set_pitchbend(int value); + void release_pedal(); + void set_program(byte program); + void set_chorus(uint chorus); + void set_effect_level(uint level); + + int update_actives(uint16 *active); + void set_pitchbend_factor(uint8 value); + void set_onoff(bool on); + void fix_after_load(); + + void update_pris(); + + void changed(byte what); +}; + +/* Abstract IMuse driver class */ +class IMuseDriver { +public: + enum { + pcMod = 1, + pcVolume = 2, + pcPedal = 4, + pcModwheel = 8, + pcPan = 16, + pcEffectLevel = 32, + pcProgram = 64, + pcChorus = 128, + pcAll = 255, + }; + + virtual void on_timer() = 0; + virtual uint32 get_base_tempo() = 0; + virtual byte get_hardware_type() = 0; + virtual void init(IMuse *eng, OSystem *syst) = 0; + virtual void update_pris() = 0; + virtual void set_instrument(uint slot, byte *instr) = 0; + virtual void part_set_instrument(Part *part, Instrument *instr) = 0; + virtual void part_key_on(Part *part, byte note, byte velocity) = 0; + virtual void part_key_off(Part *part, byte note) = 0; + virtual void part_off(Part *part) = 0; + virtual void part_changed(Part *part,byte what) = 0; + virtual void part_set_param(Part *part, byte param, int value) = 0; + virtual int part_update_active(Part *part,uint16 *active) = 0; +}; + + +// WARNING: This is the internal variant of the IMUSE class. +// imuse.h contains a public version of the same class. +// the public version, only contains a set of methods. +class IMuse { +friend struct Player; +private: + IMuseDriver *_driver; + + byte **_base_sounds; + + byte _locked; + byte _hardware_type; + +public: + bool _mt32emulate; +private: + + + bool _paused; + bool _active_volume_faders; + bool _initialized; + byte _volume_fader_counter; + + int _game_tempo; + + uint _queue_end, _queue_pos, _queue_sound; + byte _queue_adding; + + SustainingNotes *_sustain_notes_used; + SustainingNotes *_sustain_notes_free; + SustainingNotes *_sustain_notes_head; + + byte _queue_marker; + byte _queue_cleared; + byte _master_volume; + byte _music_volume; /* Global music volume. Percantage */ + + uint16 _trigger_count; + + uint16 _channel_volume[8]; + uint16 _channel_volume_eff[8]; /* NoSave */ + uint16 _volchan_table[8]; + + Player _players[8]; + SustainingNotes _sustaining_notes[24]; + VolumeFader _volume_fader[8]; + Part _parts[32]; + + uint16 _active_notes[128]; + CommandQueue _cmd_queue[64]; + + byte *findTag(int sound, char *tag, int index); + int get_queue_sound_status(int sound); + Player *allocate_player(byte priority); + void handle_marker(uint id, byte data); + int get_channel_volume(uint a); + void init_players(); + void init_parts(); + void init_volume_fader(); + void init_sustaining_notes(); + void init_queue(); + + void sequencer_timers(); + void expire_sustain_notes(); + void expire_volume_faders(); + + Part *allocate_part(byte pri); + + int enqueue_command(int a, int b, int c, int d, int e, int f, int g); + int enqueue_trigger(int sound, int marker); + int query_queue(int param); + Player *get_player_byid(int id); + + int get_volchan_entry(uint a); + int set_volchan_entry(uint a, uint b); + int set_channel_volume(uint chan, uint vol); + void update_volumes(); + void reset_tick(); + VolumeFader *allocate_volume_fader(); + + int set_volchan(int sound, int volchan); + + void fix_parts_after_load(); + void fix_players_after_load(Scumm *scumm); + + static int saveReference(IMuse *me, byte type, void *ref); + static void *loadReference(IMuse *me, byte type, int ref); + + void lock(); + void unlock(); + +public: + Part *parts_ptr() { return _parts; } + IMuseDriver *driver() { return _driver; } + + int initialize(OSystem *syst, MidiDriver *midi, SoundMixer *mixer); + + /* Public interface */ + + enum { + PROP_TEMPO_BASE = 1, + PROP_MT32_EMULATE = 2, + }; + + void on_timer(); + void pause(bool paused); + int terminate(); + int save_or_load(Serializer *ser, Scumm *scumm); + int set_music_volume(uint vol); + int get_music_volume(); + int set_master_volume(uint vol); + int get_master_volume(); + bool start_sound(int sound); + int stop_sound(int sound); + int stop_all_sounds(); + int get_sound_status(int sound); + int32 do_command(int a, int b, int c, int d, int e, int f, int g, int h); + int clear_queue(); + void setBase(byte **base); + + uint32 property(int prop, uint32 value); + + static IMuse *create(OSystem *syst, MidiDriver *midi, SoundMixer *mixer); +}; + + +/* IMuseAdlib classes */ + +struct Struct10 { + byte active; + int16 cur_val; + int16 count; + uint16 param; + int16 start_value; + byte loop; + byte table_a[4]; + byte table_b[4]; + int8 unk3; + int8 modwheel; + int8 modwheel_last; + uint16 speed_lo_max; + uint16 num_steps; + int16 speed_hi; + int8 direction; + uint16 speed_lo; + uint16 speed_lo_counter; +}; + +struct Struct11 { + int16 modify_val; + byte param,flag0x40,flag0x10; + Struct10 *s10; +}; + +struct InstrumentExtra { + byte a,b,c,d,e,f,g,h; +}; + +struct Instrument { + byte flags_1; + byte oplvl_1; + byte atdec_1; + byte sustrel_1; + byte waveform_1; + byte flags_2; + byte oplvl_2; + byte atdec_2; + byte sustrel_2; + byte waveform_2; + byte feedback; + byte flags_a; + InstrumentExtra extra_a; + byte flags_b; + InstrumentExtra extra_b; + byte duration; +}; + +struct MidiChannelAdl : MidiChannel { + MidiChannelAdl *_next,*_prev; + byte _waitforpedal; + byte _note; + byte _channel; + byte _twochan; + byte _vol_1,_vol_2; + int16 _duration; + + Struct10 _s10a; + Struct11 _s11a; + Struct10 _s10b; + Struct11 _s11b; +}; + +struct IMuseAdlib : public IMuseDriver { +private: + FM_OPL *_opl; + byte *_adlib_reg_cache; + IMuse *_se; + SoundMixer *_mixer; + + int _adlib_timer_counter; + + uint16 channel_table_2[9]; + int _midichan_index; + int _next_tick; + uint16 curnote_table[9]; + MidiChannelAdl _midi_channels[9]; + + Instrument _part_instr[32]; + Instrument _glob_instr[32]; + + void adlib_key_off(int chan); + void adlib_note_on(int chan, byte note, int mod); + void adlib_note_on_ex(int chan, byte note, int mod); + int adlib_read_param(int chan, byte data); + void adlib_setup_channel(int chan, Instrument *instr, byte vol_1, byte vol_2); + byte adlib_read(byte port) { return _adlib_reg_cache[port]; } + void adlib_set_param(int channel, byte param, int value); + void adlib_key_onoff(int channel); + void adlib_write(byte port, byte value); + void adlib_playnote(int channel, int note); + + MidiChannelAdl *allocate_midichan(byte pri); + + void reset_tick(); + void mc_off(MidiChannel *mc); + + static void link_mc(Part *part, MidiChannelAdl *mc); + static void mc_inc_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11); + static void mc_init_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11, byte flags, InstrumentExtra *ie); + static void struct10_init(Struct10 *s10, InstrumentExtra *ie); + static byte struct10_ontimer(Struct10 *s10, Struct11 *s11); + static void struct10_setup(Struct10 *s10); + static int random_nr(int a); + void mc_key_on(MidiChannel *mc, byte note, byte velocity); + + static void premix_proc(void *param, int16 *buf, uint len); + +public: + IMuseAdlib(SoundMixer *mixer) { _mixer = mixer; } + void uninit(); + void init(IMuse *eng, OSystem *syst); + void update_pris() { } + void generate_samples(int16 *buf, int len); + void on_timer(); + void set_instrument(uint slot, byte *instr); + void part_set_instrument(Part *part, Instrument *instr); + void part_key_on(Part *part, byte note, byte velocity); + void part_key_off(Part *part, byte note); + void part_set_param(Part *part, byte param, int value); + void part_changed(Part *part,byte what); + void part_off(Part *part); + int part_update_active(Part *part,uint16 *active); + void adjust_priorities() {} + + uint32 get_base_tempo() { +#ifdef _WIN32_WCE + return 0x1F0000 * 2; // Sampled down to 11 kHz +#else //_WIN32_WCE + return 0x1924E0; +#endif //_WIN32_WCE + } + + byte get_hardware_type() { return 1; } +}; + + +/* IMuseGM classes */ + +class IMuseGM : public IMuseDriver { + IMuse *_se; + OSystem *_system; + MidiDriver *_md; + MidiChannelGM _midi_channels[9]; + + int16 _midi_pitchbend_last[16]; + uint8 _midi_volume_last[16]; + bool _midi_pedal_last[16]; + byte _midi_modwheel_last[16]; + byte _midi_effectlevel_last[16]; + byte _midi_chorus_last[16]; + int8 _midi_pan_last[16]; + + + void midiPitchBend(byte chan, int16 pitchbend); + void midiVolume(byte chan, byte volume); + void midiPedal(byte chan, bool pedal); + void midiModWheel(byte chan, byte modwheel); + void midiEffectLevel(byte chan, byte level); + void midiChorus(byte chan, byte chorus); + void midiControl0(byte chan, byte value); + void midiProgram(byte chan, byte program); + void midiPan(byte chan, int8 pan); + void midiNoteOn(byte chan, byte note, byte velocity); + void midiNoteOff(byte chan, byte note); + void midiSilence(byte chan); + void midiInit(); + +public: + IMuseGM(MidiDriver *midi) { _md = midi; } + + void uninit(); + void init(IMuse *eng, OSystem *os); + void update_pris(); + void part_off(Part *part); + int part_update_active(Part *part,uint16 *active); + + void on_timer() {} + void set_instrument(uint slot, byte *instr) {} + void part_set_instrument(Part *part, Instrument *instr) {} + void part_set_param(Part *part, byte param, int value) {} + void part_key_on(Part *part, byte note, byte velocity); + void part_key_off(Part *part, byte note); + void part_changed(Part *part,byte what); + + static int midi_driver_thread(void *param); + + uint32 get_base_tempo() { return 0x400000; } + byte get_hardware_type() { return 5; } +}; + + + +//********************************* +//**** IMUSE helper functions **** +//********************************* + + +static int clamp(int val, int min, int max) { if (val < min) return min; @@ -45,7 +642,7 @@ int clamp(int val, int min, int max) return val; } -int transpose_clamp(int a, int b, int c) +static int transpose_clamp(int a, int b, int c) { if (b > a) a += (b - a + 11) / 12 * 12; @@ -54,7 +651,7 @@ int transpose_clamp(int a, int b, int c) return a; } -uint32 get_delta_time(byte **s) +static uint32 get_delta_time(byte **s) { byte *d = *s, b; uint32 time = 0; @@ -66,12 +663,12 @@ uint32 get_delta_time(byte **s) return time; } -uint read_word(byte *a) +static uint read_word(byte *a) { return (a[0] << 8) + a[1]; } -void skip_midi_cmd(byte **song_ptr) +static void skip_midi_cmd(byte **song_ptr) { byte *s, code; @@ -97,7 +694,7 @@ void skip_midi_cmd(byte **song_ptr) *song_ptr = s; } -int is_note_cmd(byte **a, IsNoteCmdData * isnote) +static int is_note_cmd(byte **a, IsNoteCmdData * isnote) { byte *s = *a; byte code; @@ -142,17 +739,17 @@ int is_note_cmd(byte **a, IsNoteCmdData * isnote) /**********************************************************************/ -void SoundEngine::lock() +void IMuse::lock() { _locked++; } -void SoundEngine::unlock() +void IMuse::unlock() { _locked--; } -byte *SoundEngine::findTag(int sound, char *tag, int index) +byte *IMuse::findTag(int sound, char *tag, int index) { byte *ptr = NULL; int32 size, pos; @@ -161,7 +758,7 @@ byte *SoundEngine::findTag(int sound, char *tag, int index) ptr = _base_sounds[sound]; if (ptr == NULL) { - debug(1, "SoundEngine::findTag completely failed finding sound %d", + debug(1, "IMuse::findTag completely failed finding sound %d", sound); return 0; } @@ -176,12 +773,12 @@ byte *SoundEngine::findTag(int sound, char *tag, int index) return ptr + pos + 8; pos += READ_BE_UINT32_UNALIGNED(ptr + pos + 4) + 8; } - debug(1, "SoundEngine::findTag failed finding sound %d", sound); + debug(1, "IMuse::findTag failed finding sound %d", sound); return NULL; } -bool SoundEngine::start_sound(int sound) +bool IMuse::start_sound(int sound) { Player *player; void *mdhd; @@ -203,7 +800,7 @@ bool SoundEngine::start_sound(int sound) } -Player *SoundEngine::allocate_player(byte priority) +Player *IMuse::allocate_player(byte priority) { Player *player = _players, *best = NULL; int i; @@ -225,7 +822,7 @@ Player *SoundEngine::allocate_player(byte priority) return NULL; } -void SoundEngine::init_players() +void IMuse::init_players() { Player *player = _players; int i; @@ -236,7 +833,7 @@ void SoundEngine::init_players() } } -void SoundEngine::init_sustaining_notes() +void IMuse::init_sustaining_notes() { SustainingNotes *next = NULL, *sn = _sustaining_notes; int i; @@ -251,7 +848,7 @@ void SoundEngine::init_sustaining_notes() _sustain_notes_free = next; } -void SoundEngine::init_volume_fader() +void IMuse::init_volume_fader() { VolumeFader *vf = _volume_fader; int i; @@ -262,7 +859,7 @@ void SoundEngine::init_volume_fader() _active_volume_faders = false; } -void SoundEngine::init_parts() +void IMuse::init_parts() { Part *part; int i; @@ -273,7 +870,7 @@ void SoundEngine::init_parts() } } -int SoundEngine::stop_sound(int sound) +int IMuse::stop_sound(int sound) { Player *player = _players; int i; @@ -288,7 +885,7 @@ int SoundEngine::stop_sound(int sound) return r; } -int SoundEngine::stop_all_sounds() +int IMuse::stop_all_sounds() { Player *player = _players; int i; @@ -300,7 +897,7 @@ int SoundEngine::stop_all_sounds() return 0; } -void SoundEngine::on_timer() +void IMuse::on_timer() { if (_locked || _paused) return; @@ -315,7 +912,7 @@ void SoundEngine::on_timer() unlock(); } -void SoundEngine::sequencer_timers() +void IMuse::sequencer_timers() { Player *player = _players; int i; @@ -366,7 +963,7 @@ void Player::sequencer_timer() } } -void SoundEngine::handle_marker(uint id, byte data) +void IMuse::handle_marker(uint id, byte data) { uint16 *p; uint pos; @@ -404,14 +1001,14 @@ void SoundEngine::handle_marker(uint id, byte data) _queue_end = pos; } -int SoundEngine::get_channel_volume(uint a) +int IMuse::get_channel_volume(uint a) { if (a < 8) return _channel_volume_eff[a]; return _master_volume; } -Part *SoundEngine::allocate_part(byte pri) +Part *IMuse::allocate_part(byte pri) { Part *part, *best = NULL; int i; @@ -432,7 +1029,7 @@ Part *SoundEngine::allocate_part(byte pri) return best; } -void SoundEngine::expire_sustain_notes() +void IMuse::expire_sustain_notes() { SustainingNotes *sn, *next; Player *player; @@ -464,7 +1061,7 @@ void SoundEngine::expire_sustain_notes() } } -void SoundEngine::expire_volume_faders() +void IMuse::expire_volume_faders() { VolumeFader *vf; int i; @@ -512,7 +1109,7 @@ void VolumeFader::on_timer() } } -int SoundEngine::get_sound_status(int sound) +int IMuse::get_sound_status(int sound) { int i; Player *player; @@ -524,7 +1121,7 @@ int SoundEngine::get_sound_status(int sound) return get_queue_sound_status(sound); } -int SoundEngine::get_queue_sound_status(int sound) +int IMuse::get_queue_sound_status(int sound) { uint16 *a; int i, j; @@ -541,7 +1138,7 @@ int SoundEngine::get_queue_sound_status(int sound) return 0; } -int SoundEngine::set_volchan(int sound, int volchan) +int IMuse::set_volchan(int sound, int volchan) { int r; int i; @@ -587,7 +1184,7 @@ int SoundEngine::set_volchan(int sound, int volchan) } } -int SoundEngine::clear_queue() +int IMuse::clear_queue() { _queue_adding = false; _queue_cleared = true; @@ -597,7 +1194,7 @@ int SoundEngine::clear_queue() return 0; } -int SoundEngine::enqueue_command(int a, int b, int c, int d, int e, int f, +int IMuse::enqueue_command(int a, int b, int c, int d, int e, int f, int g) { uint16 *p; @@ -635,7 +1232,7 @@ int SoundEngine::enqueue_command(int a, int b, int c, int d, int e, int f, } } -int SoundEngine::query_queue(int param) +int IMuse::query_queue(int param) { switch (param) { case 0: /* get trigger count */ @@ -653,12 +1250,12 @@ int SoundEngine::query_queue(int param) } } -int SoundEngine::get_music_volume() +int IMuse::get_music_volume() { return _music_volume; } -int SoundEngine::set_music_volume(uint vol) +int IMuse::set_music_volume(uint vol) { if (vol > 100) vol = 100; @@ -670,7 +1267,7 @@ int SoundEngine::set_music_volume(uint vol) return 0; } -int SoundEngine::set_master_volume(uint vol) +int IMuse::set_master_volume(uint vol) { int i; if (vol > 127) @@ -680,26 +1277,26 @@ int SoundEngine::set_master_volume(uint vol) vol = vol / (100 / _music_volume); _master_volume = vol; - _s->_sound_volume_master = vol; +// _s->_sound_volume_master = vol; for (i = 0; i != 8; i++) _channel_volume_eff[i] = (_channel_volume[i] + 1) * vol >> 7; update_volumes(); return 0; } -int SoundEngine::get_master_volume() +int IMuse::get_master_volume() { return _master_volume; } -int SoundEngine::terminate() +int IMuse::terminate() { return 0; /* not implemented */ } -int SoundEngine::enqueue_trigger(int sound, int marker) +int IMuse::enqueue_trigger(int sound, int marker) { uint16 *p; uint pos; @@ -724,7 +1321,7 @@ int SoundEngine::enqueue_trigger(int sound, int marker) return 0; } -int32 SoundEngine::do_command(int a, int b, int c, int d, int e, int f, int g, +int32 IMuse::do_command(int a, int b, int c, int d, int e, int f, int g, int h) { byte cmd = a & 0xFF; @@ -754,8 +1351,12 @@ int32 SoundEngine::do_command(int a, int b, int c, int d, int e, int f, int g, return set_channel_volume(b, c); case 18: return set_volchan_entry(b, c); + + case 2: + case 3: + return 0; default: - warning("SoundEngine::do_command invalid command %d", cmd); + warning("IMuse::do_command invalid command %d", cmd); } } else if (param == 1) { @@ -826,7 +1427,7 @@ int32 SoundEngine::do_command(int a, int b, int c, int d, int e, int f, int g, case 24: return 0; default: - warning("SoundEngine::do_command default midi command %d", cmd); + warning("IMuse::do_command default midi command %d", cmd); return -1; } } @@ -834,7 +1435,7 @@ int32 SoundEngine::do_command(int a, int b, int c, int d, int e, int f, int g, return -1; } -int SoundEngine::set_channel_volume(uint chan, uint vol) +int IMuse::set_channel_volume(uint chan, uint vol) { if (chan >= 8 || vol > 127) return -1; @@ -845,7 +1446,7 @@ int SoundEngine::set_channel_volume(uint chan, uint vol) return 0; } -void SoundEngine::update_volumes() +void IMuse::update_volumes() { Player *player; int i; @@ -856,7 +1457,7 @@ void SoundEngine::update_volumes() } } -int SoundEngine::set_volchan_entry(uint a, uint b) +int IMuse::set_volchan_entry(uint a, uint b) { if (a >= 8) return -1; @@ -924,7 +1525,7 @@ int HookDatas::set(byte cls, byte value, byte chan) } -VolumeFader *SoundEngine::allocate_volume_fader() +VolumeFader *IMuse::allocate_volume_fader() { VolumeFader *vf; int i; @@ -941,7 +1542,7 @@ VolumeFader *SoundEngine::allocate_volume_fader() return vf; } -Player *SoundEngine::get_player_byid(int id) +Player *IMuse::get_player_byid(int id) { int i; Player *player, *found = NULL; @@ -956,25 +1557,55 @@ Player *SoundEngine::get_player_byid(int id) return found; } -int SoundEngine::get_volchan_entry(uint a) +int IMuse::get_volchan_entry(uint a) { if (a < 8) return _volchan_table[a]; return -1; } -int SoundEngine::initialize(Scumm *scumm, SoundDriver * driver) +uint32 IMuse::property(int prop, uint32 value) { + switch(prop) { + case PROP_TEMPO_BASE: + _game_tempo = value; + break; + + case PROP_MT32_EMULATE: + _mt32emulate = !!value; + break; + } + return 0; +} + +void IMuse::setBase(byte **base) { + _base_sounds = base; +} + + +IMuse *IMuse::create(OSystem *syst, MidiDriver *midi, SoundMixer *mixer) { + IMuse *i = new IMuse; + i->initialize(syst, midi, mixer); + return i; +} + + +int IMuse::initialize(OSystem *syst, MidiDriver *midi, SoundMixer *mixer) { int i; - if (_initialized) - return -1; + + IMuseDriver *driv; - scumm->_soundEngine = this; - _s = scumm; + if (midi == NULL) { + driv = new IMuseAdlib(mixer); + } else { + driv = new IMuseGM(midi); + } - _driver = driver; + _driver = driv; + _hardware_type = driv->get_hardware_type(); + _game_tempo = driv->get_base_tempo(); - _hardware_type = driver->get_hardware_type(); + driv->init(this,syst); _master_volume = 127; if (_music_volume < 1) @@ -989,14 +1620,12 @@ int SoundEngine::initialize(Scumm *scumm, SoundDriver * driver) init_queue(); init_parts(); - _driver->init(this, scumm->_system); - _initialized = true; return 0; } -void SoundEngine::init_queue() +void IMuse::init_queue() { _queue_adding = false; _queue_pos = 0; @@ -1004,14 +1633,12 @@ void SoundEngine::init_queue() _trigger_count = 0; } -void SoundEngine::pause(bool paused) +void IMuse::pause(bool paused) { lock(); -#if 0 int i; Part *part; - MidiChannel *mc; for (i = ARRAYSIZE(_parts), part = _parts; i != 0; i--, part++) { if (part->_player) { @@ -1020,10 +1647,9 @@ void SoundEngine::pause(bool paused) } else { part->set_vol(part->_vol); } - part->vol_changed(); + part->changed(IMuseDriver::pcVolume); } } -#endif _paused = paused; @@ -1149,11 +1775,8 @@ void Player::set_tempo(uint32 b) { uint32 i, j; - if (_se->_s->_gameTempo < 1000) - i = _se->_driver->get_base_tempo(); - else - i = _se->_s->_gameTempo; - + i = _se->_game_tempo; + j = _tempo = b; while (i & 0xFFFF0000 || j & 0xFFFF0000) { @@ -2112,7 +2735,7 @@ enum { TYPE_PLAYER = 2, }; -int SoundEngine::saveReference(SoundEngine *me, byte type, void *ref) +int IMuse::saveReference(IMuse *me, byte type, void *ref) { switch (type) { case TYPE_PART: @@ -2124,7 +2747,7 @@ int SoundEngine::saveReference(SoundEngine *me, byte type, void *ref) } } -void *SoundEngine::loadReference(SoundEngine *me, byte type, int ref) +void *IMuse::loadReference(IMuse *me, byte type, int ref) { switch (type) { case TYPE_PART: @@ -2136,19 +2759,19 @@ void *SoundEngine::loadReference(SoundEngine *me, byte type, int ref) } } -int SoundEngine::save_or_load(Serializer * ser) +int IMuse::save_or_load(Serializer * ser, Scumm *scumm) { const SaveLoadEntry mainEntries[] = { - MKLINE(SoundEngine, _queue_end, sleUint8), - MKLINE(SoundEngine, _queue_pos, sleUint8), - MKLINE(SoundEngine, _queue_sound, sleUint16), - MKLINE(SoundEngine, _queue_adding, sleByte), - MKLINE(SoundEngine, _queue_marker, sleByte), - MKLINE(SoundEngine, _queue_cleared, sleByte), - MKLINE(SoundEngine, _master_volume, sleByte), - MKLINE(SoundEngine, _trigger_count, sleUint16), - MKARRAY(SoundEngine, _channel_volume[0], sleUint16, 8), - MKARRAY(SoundEngine, _volchan_table[0], sleUint16, 8), + MKLINE(IMuse, _queue_end, sleUint8), + MKLINE(IMuse, _queue_pos, sleUint8), + MKLINE(IMuse, _queue_sound, sleUint16), + MKLINE(IMuse, _queue_adding, sleByte), + MKLINE(IMuse, _queue_marker, sleByte), + MKLINE(IMuse, _queue_cleared, sleByte), + MKLINE(IMuse, _master_volume, sleByte), + MKLINE(IMuse, _trigger_count, sleUint16), + MKARRAY(IMuse, _channel_volume[0], sleUint16, 8), + MKARRAY(IMuse, _volchan_table[0], sleUint16, 8), MKEND() }; @@ -2246,7 +2869,7 @@ int SoundEngine::save_or_load(Serializer * ser) if (!ser->isSaving()) { /* Load all sounds that we need */ - fix_players_after_load(); + fix_players_after_load(scumm); init_sustaining_notes(); _active_volume_faders = true; fix_parts_after_load(); @@ -2259,7 +2882,7 @@ int SoundEngine::save_or_load(Serializer * ser) #undef MKLINE #undef MKEND -void SoundEngine::fix_parts_after_load() +void IMuse::fix_parts_after_load() { Part *part; int i; @@ -2272,7 +2895,7 @@ void SoundEngine::fix_parts_after_load() /* Only call this routine from the main thread, * since it uses getResourceAddress */ -void SoundEngine::fix_players_after_load() +void IMuse::fix_players_after_load(Scumm *scumm) { Player *player = _players; int i; @@ -2280,7 +2903,7 @@ void SoundEngine::fix_players_after_load() for (i = ARRAYSIZE(_players); i != 0; i--, player++) { if (player->_active) { player->set_tempo(player->_tempo); - _s->getResourceAddress(rtSound, player->_id); + scumm->getResourceAddress(rtSound, player->_id); } } } @@ -2288,19 +2911,19 @@ void SoundEngine::fix_players_after_load() void Part::set_detune(int8 detune) { _detune_eff = clamp((_detune = detune) + _player->_detune, -128, 127); - changed(SoundDriver::pcMod); + changed(IMuseDriver::pcMod); } void Part::set_pitchbend(int value) { _pitchbend = value * _pitchbend_factor >> 6; - changed(SoundDriver::pcMod); + changed(IMuseDriver::pcMod); } void Part::set_vol(uint8 vol) { _vol_eff = ((_vol = vol) + 1) * _player->_vol_eff >> 7; - changed(SoundDriver::pcVolume); + changed(IMuseDriver::pcVolume); } void Part::set_pri(int8 pri) @@ -2311,38 +2934,38 @@ void Part::set_pri(int8 pri) void Part::set_pan(int8 pan) { _pan_eff = clamp((_pan = pan) + _player->_pan, -64, 63); - changed(SoundDriver::pcPan); + changed(IMuseDriver::pcPan); } void Part::set_transpose(int8 transpose) { _transpose_eff = transpose_clamp((_transpose = transpose) + _player->_transpose, -12, 12); - changed(SoundDriver::pcMod); + changed(IMuseDriver::pcMod); } void Part::set_pedal(bool value) { _pedal = value; - changed(SoundDriver::pcPedal); + changed(IMuseDriver::pcPedal); } void Part::set_modwheel(uint value) { _modwheel = value; - changed(SoundDriver::pcModwheel); + changed(IMuseDriver::pcModwheel); } void Part::set_chorus(uint chorus) { _chorus = chorus; - changed(SoundDriver::pcChorus); + changed(IMuseDriver::pcChorus); } void Part::set_effect_level(uint level) { _effect_level = level; - changed(SoundDriver::pcEffectLevel); + changed(IMuseDriver::pcEffectLevel); } void Part::fix_after_load() @@ -2388,7 +3011,7 @@ void Part::key_off(byte note) _drv->part_key_off(this, note); } -void Part::init(SoundDriver * driver) +void Part::init(IMuseDriver * driver) { _drv = driver; _player = NULL; @@ -2478,7 +3101,7 @@ void Part::set_program(byte program) if (_program != program || _bank != 0) { _program = program; _bank = 0; - changed(SoundDriver::pcProgram); + changed(IMuseDriver::pcProgram); } } @@ -2486,5 +3109,1269 @@ void Part::set_instrument(uint b) { _bank = (byte)(b >> 8); _program = (byte)b; - changed(SoundDriver::pcProgram); + changed(IMuseDriver::pcProgram); } + + +//******************************************** +//***** ADLIB PART OF IMUSE STARTS HERE ****** +//******************************************** + + +static byte lookup_table[64][32]; +const byte volume_table[] = { + 0, 4, 7, 11, + 13, 16, 18, 20, + 22, 24, 26, 27, + 29, 30, 31, 33, + 34, 35, 36, 37, + 38, 39, 40, 41, + 42, 43, 44, 44, + 45, 46, 47, 47, + 48, 49, 49, 50, + 51, 51, 52, 53, + 53, 54, 54, 55, + 55, 56, 56, 57, + 57, 58, 58, 59, + 59, 60, 60, 60, + 61, 61, 62, 62, + 62, 63, 63, 63 +}; + +int lookup_volume(int a, int b) +{ + if (b == 0) + return 0; + + if (b == 31) + return a; + + if (a < -63 || a > 63) { + return b * (a + 1) >> 5; + } + + if (b < 0) { + if (a < 0) { + return lookup_table[-a][-b]; + } else { + return -lookup_table[a][-b]; + } + } else { + if (a < 0) { + return -lookup_table[-a][b]; + } else { + return lookup_table[a][b]; + } + } +} + +void create_lookup_table() +{ + int i, j; + int sum; + + for (i = 0; i < 64; i++) { + sum = i; + for (j = 0; j < 32; j++) { + lookup_table[i][j] = sum >> 5; + sum += i; + } + } + for (i = 0; i < 64; i++) + lookup_table[i][0] = 0; +} + +MidiChannelAdl *IMuseAdlib::allocate_midichan(byte pri) +{ + MidiChannelAdl *ac, *best = NULL; + int i; + + for (i = 0; i < 9; i++) { + if (++_midichan_index >= 9) + _midichan_index = 0; + ac = &_midi_channels[_midichan_index]; + if (!ac->_part) + return ac; + if (!ac->_next) { + if (ac->_part->_pri_eff <= pri) { + pri = ac->_part->_pri_eff; + best = ac; + } + } + } + + if (best) + mc_off(best); + else; //debug(1, "Denying adlib channel request"); + return best; +} + +void IMuseAdlib::premix_proc(void *param, int16 *buf, uint len) { + ((IMuseAdlib*)param)->generate_samples(buf, len); +} + +void IMuseAdlib::init(IMuse *eng, OSystem *syst) +{ + int i; + MidiChannelAdl *mc; + + _se = eng; + + for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) { + mc->_channel = i; + mc->_s11a.s10 = &mc->_s10b; + mc->_s11b.s10 = &mc->_s10a; + } + + _adlib_reg_cache = (byte *)calloc(256, 1); + + _opl = OPLCreate(OPL_TYPE_YM3812, 3579545, syst->property(OSystem::PROP_GET_SAMPLE_RATE,0)); + + adlib_write(1, 0x20); + adlib_write(8, 0x40); + adlib_write(0xBD, 0x00); + create_lookup_table(); + + _mixer->setup_premix(this, premix_proc); +} + +void IMuseAdlib::adlib_write(byte port, byte value) +{ + if (_adlib_reg_cache[port] == value) + return; + _adlib_reg_cache[port] = value; + + OPLWriteReg(_opl, port, value); +} + +void IMuseAdlib::adlib_key_off(int chan) +{ + byte port = chan + 0xB0; + adlib_write(port, adlib_read(port) & ~0x20); +} + +struct AdlibSetParams { + byte a, b, c, d; +}; + +static const byte channel_mappings[9] = { + 0, 1, 2, 8, + 9, 10, 16, 17, + 18 +}; + +static const byte channel_mappings_2[9] = { + 3, 4, 5, 11, + 12, 13, 19, 20, + 21 +}; + +static const AdlibSetParams adlib_setparam_table[] = { + {0x40, 0, 63, 63}, /* level */ + {0xE0, 2, 0, 0}, /* unused */ + {0x40, 6, 192, 0}, /* level key scaling */ + {0x20, 0, 15, 0}, /* modulator frequency multiple */ + {0x60, 4, 240, 15}, /* attack rate */ + {0x60, 0, 15, 15}, /* decay rate */ + {0x80, 4, 240, 15}, /* sustain level */ + {0x80, 0, 15, 15}, /* release rate */ + {0xE0, 0, 3, 0}, /* waveform select */ + {0x20, 7, 128, 0}, /* amp mod */ + {0x20, 6, 64, 0}, /* vib */ + {0x20, 5, 32, 0}, /* eg typ */ + {0x20, 4, 16, 0}, /* ksr */ + {0xC0, 0, 1, 0}, /* decay alg */ + {0xC0, 1, 14, 0} /* feedback */ +}; + +void IMuseAdlib::adlib_set_param(int channel, byte param, int value) +{ + const AdlibSetParams *as; + byte port; + + assert(channel >= 0 && channel < 9); + + if (param <= 12) { + port = channel_mappings_2[channel]; + } else if (param <= 25) { + param -= 13; + port = channel_mappings[channel]; + } else if (param <= 27) { + param -= 13; + port = channel; + } else if (param == 28 || param == 29) { + if (param == 28) + value -= 15; + else + value -= 383; + value <<= 4; + channel_table_2[channel] = value; + adlib_playnote(channel, curnote_table[channel] + value); + return; + } else { + return; + } + + as = &adlib_setparam_table[param]; + if (as->d) + value = as->d - value; + port += as->a; + adlib_write(port, (adlib_read(port) & ~as->c) | (((byte)value) << as->b)); +} + +static const byte octave_numbers[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const byte note_numbers[] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 3, 4, 5, 6, 7, 8, 9, 10 +}; + +static const byte note_to_f_num[] = { + 90, 91, 92, 92, 93, 94, 94, 95, + 96, 96, 97, 98, 98, 99, 100, 101, + 101, 102, 103, 104, 104, 105, 106, 107, + 107, 108, 109, 110, 111, 111, 112, 113, + 114, 115, 115, 116, 117, 118, 119, 120, + 121, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, + 143, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 157, 158, 159, 160, + 161, 162, 163, 165, 166, 167, 168, 169, + 171, 172, 173, 174, 176, 177, 178, 180, + 181, 182, 184, 185, 186, 188, 189, 190, + 192, 193, 194, 196, 197, 199, 200, 202, + 203, 205, 206, 208, 209, 211, 212, 214, + 215, 217, 218, 220, 222, 223, 225, 226, + 228, 230, 231, 233, 235, 236, 238, 240, + 242, 243, 245, 247, 249, 251, 252, 254, +}; + +void IMuseAdlib::adlib_playnote(int channel, int note) +{ + byte old, oct, notex; + int note2; + int i; + + note2 = (note >> 7) - 4; + + oct = octave_numbers[note2] << 2; + notex = note_numbers[note2]; + + old = adlib_read(channel + 0xB0); + if (old & 0x20) { + old &= ~0x20; + if (oct > old) { + if (notex < 6) { + notex += 12; + oct -= 4; + } + } else if (oct < old) { + if (notex > 11) { + notex -= 12; + oct += 4; + } + } + } + + i = (notex << 3) + ((note >> 4) & 0x7); + adlib_write(channel + 0xA0, note_to_f_num[i]); + adlib_write(channel + 0xB0, oct | 0x20); +} + +void IMuseAdlib::adlib_note_on(int chan, byte note, int mod) +{ + int code; + assert(chan >= 0 && chan < 9); + code = (note << 7) + mod; + curnote_table[chan] = code; + adlib_playnote(chan, channel_table_2[chan] + code); +} + +void IMuseAdlib::adlib_note_on_ex(int chan, byte note, int mod) +{ + int code; + assert(chan >= 0 && chan < 9); + code = (note << 7) + mod; + curnote_table[chan] = code; + channel_table_2[chan] = 0; + adlib_playnote(chan, code); +} + +void IMuseAdlib::adlib_key_onoff(int channel) +{ + byte val; + byte port = channel + 0xB0; + assert(channel >= 0 && channel < 9); + + val = adlib_read(port); + adlib_write(port, val & ~0x20); + adlib_write(port, val | 0x20); +} + +void IMuseAdlib::adlib_setup_channel(int chan, Instrument * instr, + byte vol_1, byte vol_2) +{ + byte port; + + assert(chan >= 0 && chan < 9); + + port = channel_mappings[chan]; + adlib_write(port + 0x20, instr->flags_1); + adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1); + adlib_write(port + 0x60, ~instr->atdec_1); + adlib_write(port + 0x80, ~instr->sustrel_1); + adlib_write(port + 0xE0, instr->waveform_1); + + port = channel_mappings_2[chan]; + adlib_write(port + 0x20, instr->flags_2); + adlib_write(port + 0x40, (instr->oplvl_2 | 0x3F) - vol_2); + adlib_write(port + 0x60, ~instr->atdec_2); + adlib_write(port + 0x80, ~instr->sustrel_2); + adlib_write(port + 0xE0, instr->waveform_2); + + adlib_write((byte)chan + 0xC0, instr->feedback); +} + +int IMuseAdlib::adlib_read_param(int chan, byte param) +{ + const AdlibSetParams *as; + byte val; + byte port; + + assert(chan >= 0 && chan < 9); + + if (param <= 12) { + port = channel_mappings_2[chan]; + } else if (param <= 25) { + param -= 13; + port = channel_mappings[chan]; + } else if (param <= 27) { + param -= 13; + port = chan; + } else if (param == 28) { + return 0xF; + } else if (param == 29) { + return 0x17F; + } else { + return 0; + } + + as = &adlib_setparam_table[param]; + val = adlib_read(port + as->a); + val &= as->c; + val >>= as->b; + if (as->d) + val = as->d - val; + + return val; +} + +void IMuseAdlib::generate_samples(int16 * data, int len) +{ + int step; + + if (!_opl) { + memset(data, 0, len * sizeof(int16)); + return; + } + + do { + step = len; + if (step > _next_tick) + step = _next_tick; + YM3812UpdateOne(_opl, data, step); + + if (!(_next_tick -= step)) { + _se->on_timer(); + reset_tick(); + } + data += step; + } while (len -= step); +} + + +void IMuseAdlib::reset_tick() +{ + _next_tick = 88; +} + +void IMuseAdlib::on_timer() +{ + MidiChannelAdl *mc; + int i; + + _adlib_timer_counter += 0xD69; + while (_adlib_timer_counter >= 0x411B) { + _adlib_timer_counter -= 0x411B; + mc = _midi_channels; + for (i = 0; i != ARRAYSIZE(_midi_channels); i++, mc++) { + if (!mc->_part) + continue; + if (mc->_duration && (mc->_duration -= 0x11) <= 0) { + mc_off(mc); + return; + } + if (mc->_s10a.active) { + mc_inc_stuff(mc, &mc->_s10a, &mc->_s11a); + } + if (mc->_s10b.active) { + mc_inc_stuff(mc, &mc->_s10b, &mc->_s11b); + } + } + } +} + +const byte param_table_1[16] = { + 29, 28, 27, 0, + 3, 4, 7, 8, + 13, 16, 17, 20, + 21, 30, 31, 0 +}; + +const uint16 param_table_2[16] = { + 0x2FF, 0x1F, 0x7, 0x3F, + 0x0F, 0x0F, 0x0F, 0x3, + 0x3F, 0x0F, 0x0F, 0x0F, + 0x3, 0x3E, 0x1F, 0 +}; + +static const uint16 num_steps_table[] = { + 1, 2, 4, 5, + 6, 7, 8, 9, + 10, 12, 14, 16, + 18, 21, 24, 30, + 36, 50, 64, 82, + 100, 136, 160, 192, + 240, 276, 340, 460, + 600, 860, 1200, 1600 +}; + +int IMuseAdlib::random_nr(int a) +{ + static byte _rand_seed = 1; + if (_rand_seed & 1) { + _rand_seed >>= 1; + _rand_seed ^= 0xB8; + } else { + _rand_seed >>= 1; + } + return _rand_seed * a >> 8; +} + +void IMuseAdlib::struct10_setup(Struct10 * s10) +{ + int b, c, d, e, f, g, h; + byte t; + + b = s10->unk3; + f = s10->active - 1; + + t = s10->table_a[f]; + e = num_steps_table[lookup_table[t & 0x7F][b]]; + if (t & 0x80) { + e = random_nr(e); + } + if (e == 0) + e++; + + s10->num_steps = s10->speed_lo_max = e; + + if (f != 2) { + c = s10->param; + g = s10->start_value; + t = s10->table_b[f]; + d = lookup_volume(c, (t & 0x7F) - 31); + if (t & 0x80) { + d = random_nr(d); + } + if (d + g > c) { + h = c - g; + } else { + h = d; + if (d + g < 0) + h = -g; + } + h -= s10->cur_val; + } else { + h = 0; + } + + s10->speed_hi = h / e; + if (h < 0) { + h = -h; + s10->direction = -1; + } else { + s10->direction = 1; + } + + s10->speed_lo = h % e; + s10->speed_lo_counter = 0; +} + +byte IMuseAdlib::struct10_ontimer(Struct10 * s10, Struct11 * s11) +{ + byte result = 0; + int i; + + if (s10->count && (s10->count -= 17) <= 0) { + s10->active = 0; + return 0; + } + + i = s10->cur_val + s10->speed_hi; + s10->speed_lo_counter += s10->speed_lo; + if (s10->speed_lo_counter >= s10->speed_lo_max) { + s10->speed_lo_counter -= s10->speed_lo_max; + i += s10->direction; + } + if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) { + s10->cur_val = i; + s10->modwheel_last = s10->modwheel; + i = lookup_volume(i, s10->modwheel_last); + if (i != s11->modify_val) { + s11->modify_val = i; + result = 1; + } + } + + if (!--s10->num_steps) { + s10->active++; + if (s10->active > 4) { + if (s10->loop) { + s10->active = 1; + result |= 2; + struct10_setup(s10); + } else { + s10->active = 0; + } + } else { + struct10_setup(s10); + } + } + + return result; +} + +void IMuseAdlib::struct10_init(Struct10 * s10, InstrumentExtra * ie) +{ + s10->active = 1; + s10->cur_val = 0; + s10->modwheel_last = 31; + s10->count = ie->a; + if (s10->count) + s10->count *= 63; + s10->table_a[0] = ie->b; + s10->table_a[1] = ie->d; + s10->table_a[2] = ie->f; + s10->table_a[3] = ie->g; + + s10->table_b[0] = ie->c; + s10->table_b[1] = ie->e; + s10->table_b[2] = 0; + s10->table_b[3] = ie->h; + + struct10_setup(s10); +} + +void IMuseAdlib::mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, + Struct11 * s11, byte flags, + InstrumentExtra * ie) +{ + Part *part = mc->_part; + + s11->modify_val = 0; + s11->flag0x40 = flags & 0x40; + s10->loop = flags & 0x20; + s11->flag0x10 = flags & 0x10; + s11->param = param_table_1[flags & 0xF]; + s10->param = param_table_2[flags & 0xF]; + s10->unk3 = 31; + if (s11->flag0x40) { + s10->modwheel = part->_modwheel >> 2; + } else { + s10->modwheel = 31; + } + + switch (s11->param) { + case 0: + s10->start_value = mc->_vol_2; + break; + case 13: + s10->start_value = mc->_vol_1; + break; + case 30: + s10->start_value = 31; + s11->s10->modwheel = 0; + break; + case 31: + s10->start_value = 0; + s11->s10->unk3 = 0; + break; + default: + s10->start_value = ((IMuseAdlib*)part->_drv)->adlib_read_param(mc->_channel, s11->param); + } + + struct10_init(s10, ie); +} + +void IMuseAdlib::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, + Struct11 * s11) +{ + byte code; + Part *part = mc->_part; + + code = struct10_ontimer(s10, s11); + + if (code & 1) { + switch (s11->param) { + case 0: + mc->_vol_2 = s10->start_value + s11->modify_val; + ((IMuseAdlib*)part->_drv)->adlib_set_param(mc->_channel, 0, + volume_table[lookup_table[mc->_vol_2] + [part->_vol_eff >> 2]]); + break; + case 13: + mc->_vol_1 = s10->start_value + s11->modify_val; + if (mc->_twochan) { + ((IMuseAdlib*)part->_drv)->adlib_set_param(mc->_channel, 13, + volume_table[lookup_table[mc->_vol_1] + [part->_vol_eff >> 2]]); + } else { + ((IMuseAdlib*)part->_drv)->adlib_set_param(mc->_channel, 13, mc->_vol_1); + } + break; + case 30: + s11->s10->modwheel = (char)s11->modify_val; + break; + case 31: + s11->s10->unk3 = (char)s11->modify_val; + break; + default: + ((IMuseAdlib*)part->_drv)->adlib_set_param(mc->_channel, s11->param, + s10->start_value + s11->modify_val); + break; + } + } + + if (code & 2 && s11->flag0x10) + ((IMuseAdlib*)part->_drv)->adlib_key_onoff(mc->_channel); +} + +void IMuseAdlib::part_changed(Part *part, byte what) +{ + MidiChannelAdl *mc; + + if (what & pcProgram) { + if (part->_program < 32) { + part_set_instrument(part, &_glob_instr[part->_program]); + } + } + + if (what & pcMod) { + for (mc = part->_mc->adl(); mc; mc = mc->_next) { + adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + part->_pitchbend + part->_detune_eff); + } + } + + if (what & pcVolume) { + for (mc = part->_mc->adl(); mc; mc = mc->_next) { + adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2] + [part->_vol_eff >> 2]]); + if (mc->_twochan) { + adlib_set_param(mc->_channel, 13, + volume_table[lookup_table[mc->_vol_1] + [part->_vol_eff >> 2]]); + } + } + } + + if (what & pcPedal) { + if (!part->_pedal) { + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_waitforpedal) + mc_off(mc); + } + } + } + + if (what & pcModwheel) { + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_s10a.active && mc->_s11a.flag0x40) + mc->_s10a.modwheel = part->_modwheel >> 2; + if (mc->_s10b.active && mc->_s11b.flag0x40) + mc->_s10b.modwheel = part->_modwheel >> 2; + } + } +} + +void IMuseAdlib::mc_key_on(MidiChannel * mc2, byte note, byte velocity) +{ + MidiChannelAdl *mc = (MidiChannelAdl *)mc2; + Part *part = mc->_part; + Instrument *instr = &_part_instr[part->_slot]; + int c; + byte vol_1, vol_2; + + mc->_twochan = instr->feedback & 1; + mc->_note = note; + mc->_waitforpedal = false; + mc->_duration = instr->duration; + if (mc->_duration != 0) + mc->_duration *= 63; + + vol_1 = + (instr->oplvl_1 & 0x3F) + + lookup_table[velocity >> 1][instr->waveform_1 >> 2]; + if (vol_1 > 0x3F) + vol_1 = 0x3F; + mc->_vol_1 = vol_1; + + vol_2 = + (instr->oplvl_2 & 0x3F) + + lookup_table[velocity >> 1][instr->waveform_2 >> 2]; + if (vol_2 > 0x3F) + vol_2 = 0x3F; + mc->_vol_2 = vol_2; + + c = part->_vol_eff >> 2; + + vol_2 = volume_table[lookup_table[vol_2][c]]; + if (mc->_twochan) + vol_1 = volume_table[lookup_table[vol_1][c]]; + + adlib_setup_channel(mc->_channel, instr, vol_1, vol_2); + adlib_note_on_ex(mc->_channel, part->_transpose_eff + note, + part->_detune_eff + part->_pitchbend); + + if (instr->flags_a & 0x80) { + mc_init_stuff(mc, &mc->_s10a, &mc->_s11a, instr->flags_a, + &instr->extra_a); + } else { + mc->_s10a.active = 0; + } + + if (instr->flags_b & 0x80) { + mc_init_stuff(mc, &mc->_s10b, &mc->_s11b, instr->flags_b, + &instr->extra_b); + } else { + mc->_s10b.active = 0; + } +} + +void IMuseAdlib::set_instrument(uint slot, byte *data) +{ + if (slot < 32) { + memcpy(&_glob_instr[slot], data, sizeof(Instrument)); + } +} + + +void IMuseAdlib::link_mc(Part *part, MidiChannelAdl *mc) +{ + mc->_part = part; + mc->_next = (MidiChannelAdl *)part->_mc; + part->_mc = mc; + mc->_prev = NULL; + + if (mc->_next) + mc->_next->_prev = mc; +} + +void IMuseAdlib::part_key_on(Part *part, byte note, byte velocity) +{ + MidiChannelAdl *mc; + + mc = allocate_midichan(part->_pri_eff); + if (!mc) + return; + + link_mc(part, mc); + mc_key_on(mc, note, velocity); +} + +void IMuseAdlib::part_key_off(Part *part, byte note) +{ + MidiChannelAdl *mc; + + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + if (mc->_note == note) { + if (part->_pedal) + mc->_waitforpedal = true; + else + mc_off(mc); + } + } +} + +struct AdlibInstrSetParams { + byte param; + byte shl; + byte mask; +}; + +#define MKLINE(_a_,_b_,_c_) { (int)&((Instrument*)0)->_a_, _b_, ((1<<(_c_))-1)<<(_b_) } +static const AdlibInstrSetParams adlib_instr_params[69] = { + MKLINE(oplvl_2, 0, 6), + MKLINE(waveform_2, 2, 5), + MKLINE(oplvl_2, 6, 2), + MKLINE(flags_2, 0, 4), + MKLINE(atdec_2, 4, 4), + MKLINE(atdec_2, 0, 4), + MKLINE(sustrel_2, 4, 4), + MKLINE(sustrel_2, 0, 4), + MKLINE(waveform_2, 0, 2), + MKLINE(flags_2, 7, 1), + MKLINE(flags_2, 6, 1), + MKLINE(flags_2, 5, 1), + MKLINE(flags_2, 4, 1), + + MKLINE(oplvl_1, 0, 6), + MKLINE(waveform_1, 2, 5), + MKLINE(oplvl_1, 6, 2), + MKLINE(flags_1, 0, 4), + MKLINE(atdec_1, 4, 4), + MKLINE(atdec_1, 0, 4), + MKLINE(sustrel_1, 4, 4), + MKLINE(sustrel_1, 0, 4), + MKLINE(waveform_1, 0, 2), + MKLINE(flags_1, 7, 1), + MKLINE(flags_1, 6, 1), + MKLINE(flags_1, 5, 1), + MKLINE(flags_1, 4, 1), + + MKLINE(feedback, 0, 1), + MKLINE(feedback, 1, 3), + + MKLINE(flags_a, 7, 1), + MKLINE(flags_a, 6, 1), + MKLINE(flags_a, 5, 1), + MKLINE(flags_a, 4, 1), + MKLINE(flags_a, 0, 4), + MKLINE(extra_a.a, 0, 8), + MKLINE(extra_a.b, 0, 7), + MKLINE(extra_a.c, 0, 7), + MKLINE(extra_a.d, 0, 7), + MKLINE(extra_a.e, 0, 7), + MKLINE(extra_a.f, 0, 7), + MKLINE(extra_a.g, 0, 7), + MKLINE(extra_a.h, 0, 7), + MKLINE(extra_a.b, 7, 1), + MKLINE(extra_a.c, 7, 1), + MKLINE(extra_a.d, 7, 1), + MKLINE(extra_a.e, 7, 1), + MKLINE(extra_a.f, 7, 1), + MKLINE(extra_a.g, 7, 1), + MKLINE(extra_a.h, 7, 1), + + MKLINE(flags_b, 7, 1), + MKLINE(flags_b, 6, 1), + MKLINE(flags_b, 5, 1), + MKLINE(flags_b, 4, 1), + MKLINE(flags_b, 0, 4), + MKLINE(extra_b.a, 0, 8), + MKLINE(extra_b.b, 0, 7), + MKLINE(extra_b.c, 0, 7), + MKLINE(extra_b.d, 0, 7), + MKLINE(extra_b.e, 0, 7), + MKLINE(extra_b.f, 0, 7), + MKLINE(extra_b.g, 0, 7), + MKLINE(extra_b.h, 0, 7), + MKLINE(extra_b.b, 7, 1), + MKLINE(extra_b.c, 7, 1), + MKLINE(extra_b.d, 7, 1), + MKLINE(extra_b.e, 7, 1), + MKLINE(extra_b.f, 7, 1), + MKLINE(extra_b.g, 7, 1), + MKLINE(extra_b.h, 7, 1), + + MKLINE(duration, 0, 8), +}; +#undef MKLINE + +void IMuseAdlib::part_set_param(Part *part, byte param, int value) +{ + const AdlibInstrSetParams *sp = &adlib_instr_params[param]; + byte *p = (byte *)&_part_instr[part->_slot] + sp->param; + *p = (*p & ~sp->mask) | (value << sp->shl); + + if (param < 28) { + MidiChannelAdl *mc; + + for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) { + adlib_set_param(mc->_channel, param, value); + } + } +} + +void IMuseAdlib::part_off(Part *part) +{ + MidiChannelAdl *mc = (MidiChannelAdl *)part->_mc; + part->_mc = NULL; + for (; mc; mc = mc->_next) { + mc_off(mc); + } +} + +void IMuseAdlib::mc_off(MidiChannel * mc2) +{ + MidiChannelAdl *mc = (MidiChannelAdl *)mc2, *tmp; + + adlib_key_off(mc->_channel); + + tmp = mc->_prev; + + if (mc->_next) + mc->_next->_prev = tmp; + if (tmp) + tmp->_next = mc->_next; + else + mc->_part->_mc = mc->_next; + mc->_part = NULL; +} + +void IMuseAdlib::part_set_instrument(Part *part, Instrument * instr) +{ + Instrument *i = &_part_instr[part->_slot]; + memcpy(i, instr, sizeof(Instrument)); +} + +int IMuseAdlib::part_update_active(Part *part, uint16 *active) +{ + uint16 bits; + int count = 0; + MidiChannelAdl *mc; + + bits = 1 << part->_chan; + + for (mc = part->_mc->adl(); mc; mc = mc->_next) { + if (!(active[mc->_note] & bits)) { + active[mc->_note] |= bits; + count++; + } + } + return count; +} + +//******************************************** +//** GENERAL MIDI PART OF IMUSE STARTS HERE ** +//******************************************** + +void IMuseGM::midiPitchBend(byte chan, int16 pitchbend) +{ + uint16 tmp; + + if (_midi_pitchbend_last[chan] != pitchbend) { + _midi_pitchbend_last[chan] = pitchbend; + tmp = (pitchbend << 2) + 0x2000; + _md->send(((tmp >> 7) & 0x7F) << 16 | (tmp & 0x7F) << 8 | 0xE0 | chan); + } +} + +void IMuseGM::midiVolume(byte chan, byte volume) +{ + if (_midi_volume_last[chan] != volume) { + _midi_volume_last[chan] = volume; + _md->send(volume << 16 | 7 << 8 | 0xB0 | chan); + } +} +void IMuseGM::midiPedal(byte chan, bool pedal) +{ + if (_midi_pedal_last[chan] != pedal) { + _midi_pedal_last[chan] = pedal; + _md->send(pedal << 16 | 64 << 8 | 0xB0 | chan); + } +} + +void IMuseGM::midiModWheel(byte chan, byte modwheel) +{ + if (_midi_modwheel_last[chan] != modwheel) { + _midi_modwheel_last[chan] = modwheel; + _md->send(modwheel << 16 | 1 << 8 | 0xB0 | chan); + } +} + +void IMuseGM::midiEffectLevel(byte chan, byte level) +{ + if (_midi_effectlevel_last[chan] != level) { + _midi_effectlevel_last[chan] = level; + _md->send(level << 16 | 91 << 8 | 0xB0 | chan); + } +} + +void IMuseGM::midiChorus(byte chan, byte chorus) +{ + if (_midi_chorus_last[chan] != chorus) { + _midi_chorus_last[chan] = chorus; + _md->send(chorus << 16 | 93 << 8 | 0xB0 | chan); + } +} + +void IMuseGM::midiControl0(byte chan, byte value) +{ + _md->send(value << 16 | 0 << 8 | 0xB0 | chan); +} + + +void IMuseGM::midiProgram(byte chan, byte program) +{ + if ((chan + 1) != 10) { /* Ignore percussion prededed by patch change */ + if (_se->_mt32emulate) + program = mt32_to_gmidi[program]; + + _md->send(program << 8 | 0xC0 | chan); + } +} + +void IMuseGM::midiPan(byte chan, int8 pan) +{ + if (_midi_pan_last[chan] != pan) { + _midi_pan_last[chan] = pan; + _md->send(((pan - 64) & 0x7F) << 16 | 10 << 8 | 0xB0 | chan); + } +} + +void IMuseGM::midiNoteOn(byte chan, byte note, byte velocity) +{ + _md->send(velocity << 16 | note << 8 | 0x90 | chan); +} + +void IMuseGM::midiNoteOff(byte chan, byte note) +{ + _md->send(note << 8 | 0x80 | chan); +} + +void IMuseGM::midiSilence(byte chan) +{ + _md->send((64 << 8) | 0xB0 | chan); + _md->send((123 << 8) | 0xB0 | chan); +} + + +void IMuseGM::part_key_on(Part *part, byte note, byte velocity) +{ + MidiChannelGM *mc = part->_mc->gm(); + + if (mc) { + mc->_actives[note >> 4] |= (1 << (note & 0xF)); + midiNoteOn(mc->_chan, note, velocity); + } else if (part->_percussion) { + midiVolume(SPECIAL_CHANNEL, part->_vol_eff); + midiProgram(SPECIAL_CHANNEL, part->_bank); + midiNoteOn(SPECIAL_CHANNEL, note, velocity); + } +} + +void IMuseGM::part_key_off(Part *part, byte note) +{ + MidiChannelGM *mc = part->_mc->gm(); + + if (mc) { + mc->_actives[note >> 4] &= ~(1 << (note & 0xF)); + midiNoteOff(mc->_chan, note); + } else if (part->_percussion) { + midiNoteOff(SPECIAL_CHANNEL, note); + } +} + +int IMuseGM::midi_driver_thread(void *param) { + IMuseGM *mid = (IMuseGM*) param; + int old_time, cur_time; + + old_time = mid->_system->get_msecs(); + + for(;;) { + mid->_system->delay_msecs(10); + + cur_time = mid->_system->get_msecs(); + while (old_time < cur_time) { + old_time += 10; + mid->_se->on_timer(); + } + } +} + +void IMuseGM::init(IMuse *eng, OSystem *syst) +{ + int i; + MidiChannelGM *mc; + + _system = syst; + + /* open midi driver */ + int result = _md->open(MidiDriver::MO_SIMPLE); + if (result) + error("IMuseGM::error = %s", MidiDriver::get_error_name(result)); + + /* Install the on_timer thread */ + syst->create_thread(midi_driver_thread, this); + _se = eng; + + for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) + mc->_chan = i; +} + +void IMuseGM::update_pris() +{ + Part *part, *hipart; + int i; + byte hipri, lopri; + MidiChannelGM *mc, *lomc; + + while (true) { + hipri = 0; + hipart = NULL; + for (i = 32, part = _se->parts_ptr(); i; i--, part++) { + if (part->_player && !part->_percussion && part->_on && !part->_mc + && part->_pri_eff >= hipri) { + hipri = part->_pri_eff; + hipart = part; + } + } + + if (!hipart) + return; + + lopri = 255; + lomc = NULL; + for (i = ARRAYSIZE(_midi_channels), mc = _midi_channels;; mc++) { + if (!mc->_part) { + lomc = mc; + break; + } + if (mc->_part->_pri_eff <= lopri) { + lopri = mc->_part->_pri_eff; + lomc = mc; + } + + if (!--i) { + if (lopri >= hipri) + return; + lomc->_part->off(); + break; + } + } + + hipart->_mc = lomc; + lomc->_part = hipart; + hipart->changed(pcAll); + } +} + +int IMuseGM::part_update_active(Part *part, uint16 *active) +{ + int i, j; + uint16 *act, mask, bits; + int count = 0; + + bits = 1 << part->_chan; + + act = part->_mc->gm()->_actives; + + for (i = 8; i; i--) { + mask = *act++; + if (mask) { + for (j = 16; j; j--, mask >>= 1, active++) { + if (mask & 1 && !(*active & bits)) { + *active |= bits; + count++; + } + } + } else { + active += 16; + } + } + return count; +} + +void IMuseGM::part_changed(Part *part, byte what) +{ + MidiChannelGM *mc; + + /* Mark for re-schedule if program changed when in pre-state */ + if (what & pcProgram && part->_percussion) { + part->_percussion = false; + update_pris(); + } + + if (!(mc = part->_mc->gm())) + return; + + if (what & pcMod) + midiPitchBend(mc->_chan, + clamp(part->_pitchbend + part->_detune_eff + + (part->_transpose_eff << 7), -2048, 2047)); + + if (what & pcVolume) + midiVolume(mc->_chan, part->_vol_eff); + + if (what & pcPedal) + midiPedal(mc->_chan, part->_pedal); + + if (what & pcModwheel) + midiModWheel(mc->_chan, part->_modwheel); + + if (what & pcPan) + midiPan(mc->_chan, part->_pan_eff); + + if (what & pcEffectLevel) + midiEffectLevel(mc->_chan, part->_effect_level); + + if (what & pcProgram) { + if (part->_bank) { + midiControl0(mc->_chan, part->_bank); + midiProgram(mc->_chan, part->_program); + midiControl0(mc->_chan, 0); + } else { + midiProgram(mc->_chan, part->_program); + } + } + + if (what & pcChorus) + midiChorus(mc->_chan, part->_effect_level); +} + + +void IMuseGM::part_off(Part *part) +{ + MidiChannelGM *mc = part->_mc->gm(); + if (mc) { + part->_mc = NULL; + mc->_part = NULL; + memset(mc->_actives, 0, sizeof(mc->_actives)); + midiSilence(mc->_chan); + } +} + diff --git a/sound/imuse.h b/sound/imuse.h new file mode 100644 index 00000000000..fc2cacbd0df --- /dev/null +++ b/sound/imuse.h @@ -0,0 +1,46 @@ + +//WARNING: These is only the public interface to the IMUSE class +//This is safe as long as none of the methods are virtual, +//and as long as no variables are put here. +//Removing the private parts from the public class definition, +//means that the internals of IMuse can change without having to +//recompile all files that depend on this interface. +//Also, it probably decreases compile times, since the IMuse specific +//classes only will be parsed once (which is when imuse.cpp is compiled) + + +//If you change stuff here, you *MUST* change stuff in imuse.cpp as well + +class IMuse { +public: + /* making a dummy constructor means that this object will never be + * instanciated on its own */ + +public: + enum { + PROP_TEMPO_BASE = 1, + PROP_MT32_EMULATE = 2, + }; + + void on_timer(); + void pause(bool paused); + int terminate(); + int save_or_load(Serializer *ser, Scumm *scumm); + int set_music_volume(uint vol); + int get_music_volume(); + int set_master_volume(uint vol); + int get_master_volume(); + bool start_sound(int sound); + int stop_sound(int sound); + int stop_all_sounds(); + int get_sound_status(int sound); + int32 do_command(int a, int b, int c, int d, int e, int f, int g, int h); + int clear_queue(); + void setBase(byte **base); + uint32 property(int prop, uint32 value); + + static IMuse *create(OSystem *syst, MidiDriver *midi, SoundMixer *mixer); + + static IMuse *create_adlib(OSystem *syst, SoundMixer *mixer) { return create(syst, NULL, mixer); } + static IMuse *create_midi(OSystem *syst, MidiDriver *midi) { return create(syst, midi, NULL); } +}; diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp index 7a881e7cb1b..b8d365be292 100644 --- a/sound/mididrv.cpp +++ b/sound/mididrv.cpp @@ -30,11 +30,9 @@ #include #endif - #include "stdafx.h" #include "scumm.h" -#include "gmidi.h" - +#include "mididrv.h" #ifdef WIN32 @@ -326,9 +324,6 @@ const char *MidiDriver::get_error_name(int error_code) { #if 0 - - - void MidiDriver::midiInit() { if (MidiInitialized != true) { @@ -686,4 +681,51 @@ void MidiDriver::midiInitNull() warning ("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib"); } -#endif \ No newline at end of file + + + +/* old header stuff.. */ +/* General Midi header file */ +#define SEQ_MIDIPUTC 5 +#define SPECIAL_CHANNEL 9 +#define DEVICE_NUM 0 + + + +#ifdef __APPLE__CW + #include + #include "QuickTimeMusic.h" + + NoteAllocator qtNoteAllocator; + NoteChannel qtNoteChannel[16]; + NoteRequest simpleNoteRequest; +#endif + +#ifdef WIN32 + #include +#elif defined(UNIX) + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#ifdef __MORPHOS__ + #include + #include + + #define NO_PPCINLINE_STDARG + #define NO_PPCINLINE_VARARGS + #include + #include + #undef CMD_INVALID + + extern struct IOMidiRequest *ScummMidiRequest; +#endif + +#endif /* 0 */ \ No newline at end of file diff --git a/sound/gmidi.h b/sound/mididrv.h similarity index 57% rename from sound/gmidi.h rename to sound/mididrv.h index 7e9d7e8db5f..228e36ee7e4 100644 --- a/sound/gmidi.h +++ b/sound/mididrv.h @@ -1,11 +1,3 @@ -#if !defined(gmidi_h) -#define gmidi_h - -/* General Midi header file */ -#define SEQ_MIDIPUTC 5 -#define SPECIAL_CHANNEL 9 -#define DEVICE_NUM 0 - struct MidiEvent { uint32 delta; uint32 event; @@ -105,56 +97,3 @@ MidiDriver *MidiDriver_TIMIDITY_create(); MidiDriver *MidiDriver_SEQ_create(); MidiDriver *MidiDriver_QT_create(); MidiDriver *MidiDriver_AMIDI_create(); - - - -/* Roland to General Midi patch table. Still needs much work. */ -static const byte mt32_to_gmidi[128] = { - 0, 1, 2, 4, 4, 5, 5, 3, 16, 17, 18, 18, 19, - 19, 20, 21, 6, 6, 6, 7, 7, 7, 8, 8, 62, 63, - 62, 63, 38, 39, 38, 39, 88, 89, 52, 113, 97, 96, 91, - 85, 14, 101, 68, 95, 86, 103, 88, 80, 48, 49, 51, 45, - 40, 40, 42, 42, 43, 46, 46, 24, 25, 26, 27, 104, 32, - 33, 34, 39, 36, 37, 38, 35, 79, 73, 72, 72, 74, 75, - 64, 65, 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, - 63, 60, 60, 58, 61, 61, 11, 11, 12, 88, 9, 14, 13, - 12, 107, 111, 77, 78, 78, 76, 121, 47, 117, 127, 115, 118, - 116, 118, 94, 115, 9, 55, 124, 123, 125, 126, 127 -}; - -#ifdef __APPLE__CW - #include - #include "QuickTimeMusic.h" - - NoteAllocator qtNoteAllocator; - NoteChannel qtNoteChannel[16]; - NoteRequest simpleNoteRequest; -#endif - -#ifdef WIN32 - #include -#elif defined(UNIX) - #include - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#ifdef __MORPHOS__ - #include - #include - - #define NO_PPCINLINE_STDARG - #define NO_PPCINLINE_VARARGS - #include - #include - #undef CMD_INVALID - - extern struct IOMidiRequest *ScummMidiRequest; -#endif -#endif /* defined(gmidi_h) */ diff --git a/sound/mixer.cpp b/sound/mixer.cpp new file mode 100644 index 00000000000..add23d9e91a --- /dev/null +++ b/sound/mixer.cpp @@ -0,0 +1,491 @@ +#include "stdafx.h" +#include "scumm.h" +#include "cdmusic.h" + +void SoundMixer::uninsert(Channel *chan) { + + for(int i=0; i!=NUM_CHANNELS; i++) { + if (_channels[i] == chan) { + if (_handles[i]) { + *_handles[i] = 0; + _handles[i] = NULL; + } + _channels[i] = NULL; + return; + } + } + error("SoundMixer::channel_deleted chan not found"); +} + +void SoundMixer::insert(PlayingSoundHandle *handle, Channel *chan) { + for(int i=0; i!=NUM_CHANNELS; i++) { + if (_channels[i] == NULL) { + _channels[i] = chan; + _handles[i] = handle; + if (handle) + *handle = i + 1; + return; + } + } + + warning("SoundMixer::insert out of mixer slots"); + chan->destroy(); +} + + +void SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags) { + insert(handle, new Channel_RAW(this, sound, size, rate, flags)); +} + +void SoundMixer::mix(int16 *buf, uint len) { + if (_premix_proc) { + _premix_proc(_premix_param, buf, len); + } else { + /* no premixer available, zero the buf out */ + memset(buf, 0, len * sizeof(int16)); + } + + /* now mix all channels */ + for(int i=0; i!=NUM_CHANNELS; i++) + if (_channels[i]) + _channels[i]->mix(buf, len); +} + +void SoundMixer::on_generate_samples(void *s, byte *samples, int len) { + ((SoundMixer*)s)->mix((int16*)samples, len>>1); +} + +void SoundMixer::bind_to_system(OSystem *syst) { + _volume_table = (int16*)calloc(256*sizeof(int16),1); + + uint rate = (uint)syst->property(OSystem::PROP_GET_SAMPLE_RATE, 0); + + _output_rate = rate; + + if (rate == 0) + error("OSystem returned invalid sample rate"); + + syst->set_sound_proc(this, on_generate_samples, OSystem::SOUND_16BIT); +} + +void SoundMixer::stop_all() { + for(int i=0; i!=NUM_CHANNELS; i++) + if (_channels[i]) + _channels[i]->destroy(); +} + +void SoundMixer::stop(PlayingSoundHandle psh) { + if (psh && _channels[psh-1]) + _channels[psh-1]->destroy(); +} + + +bool SoundMixer::has_active_channel() { + for(int i=0; i!=NUM_CHANNELS; i++) + if (_channels[i]) + return true; + return false; +} + +void SoundMixer::setup_premix(void *param, PremixProc *proc) { + _premix_param = param; + _premix_proc = proc; +} + +void SoundMixer::set_volume(int volume) { + for(int i=0; i!=256; i++) + _volume_table[i] =((int8)i) * volume; +} + + +/* RAW mixer */ +SoundMixer::Channel_RAW::Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags) { + _mixer = mixer; + _flags = flags; + _ptr = sound; + _pos = 0; + _fp_pos = 0; + _fp_speed = (1 << 16) * rate / mixer->_output_rate; + + /* adjust the magnitute to prevent division error */ + while (size & 0xFFFF0000) + size >>= 1, rate >>= 1; + + _size = size * mixer->_output_rate / rate; +} + +void SoundMixer::Channel_RAW::mix(int16 *data, uint len) { + byte *s, *s_org = NULL; + uint32 fp_pos; + + if (len > _size) + len = _size; + _size -= len; + + /* + * simple support for fread() reading of samples + */ + if (_flags & FLAG_FILE) { + /* determine how many samples to read from the file */ + uint num = len * _fp_speed >> 16; + + s_org = (byte*)malloc(num); + if (s_org == NULL) + error("Channel_RAW::mix out of memory"); + + uint num_read = fread(s_org, 1, num, (FILE*)_ptr); + if (num - num_read != 0) + memset(s_org + num_read, 0x80, num - num_read); + + s = s_org; + fp_pos = 0; + } else { + s = (byte*)_ptr + _pos; + fp_pos = _fp_pos; + } + + const uint32 fp_speed = _fp_speed; + const int16 *vol_tab = _mixer->_volume_table; + + if (_flags & FLAG_UNSIGNED) { + do { + fp_pos += fp_speed; + *data++ += vol_tab[*s ^ 0x80]; + s += fp_pos >> 16; + fp_pos &= 0x0000FFFF; + } while (--len); + } else { + do { + fp_pos += fp_speed; + *data++ += vol_tab[*s]; + s += fp_pos >> 16; + fp_pos &= 0x0000FFFF; + } while (--len); + } + + _pos = s - (byte*) _ptr; + _fp_pos = fp_pos; + + if (_flags & FLAG_FILE) { + free(s_org); + } + + if (!_size) + destroy(); +} + +void SoundMixer::Channel_RAW::destroy() { + if (_flags & FLAG_AUTOFREE) + free(_ptr); + _mixer->uninsert(this); + delete this; +} + + +/* MP3 mixer goes here */ + +#if 0 + +#ifdef COMPRESSED_SOUND_FILE +void Scumm::playSfxSound_MP3(void *sound, uint32 size) +{ + MixerChannel *mc = allocateMixer(); + + if (!mc) { + warning("No mixer channel available"); + return; + } + + mc->type = MIXER_MP3; + mc->_sfx_sound = sound; + + mad_stream_init(&mc->sound_data.mp3.stream); + + + +#ifdef _WIN32_WCE + + // 11 kHz on WinCE + + mad_stream_options((mad_stream *) & mc->sound_data.mp3.stream, + MAD_OPTION_HALFSAMPLERATE); + +#endif + + + mad_frame_init(&mc->sound_data.mp3.frame); + mad_synth_init(&mc->sound_data.mp3.synth); + mc->sound_data.mp3.position = 0; + mc->sound_data.mp3.pos_in_frame = 0xFFFFFFFF; + mc->sound_data.mp3.size = size; + /* This variable is the number of samples to cut at the start of the MP3 + file. This is needed to have lip-sync as the MP3 file have some miliseconds + of blank at the start (as, I suppose, the MP3 compression algorithm need to + have some silence at the start to really be efficient and to not distort + too much the start of the sample). + + This value was found by experimenting out. If you recompress differently your + .SO3 file, you may have to change this value. + + When using Lame, it seems that the sound starts to have some volume about 50 ms + from the start of the sound => we skip about 1024 samples. + */ + mc->sound_data.mp3.silence_cut = 1024; +} +#endif + +#ifdef COMPRESSED_SOUND_FILE +static inline int scale_sample(mad_fixed_t sample) +{ + /* round */ + sample += (1L << (MAD_F_FRACBITS - 16)); + + /* clip */ + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + /* quantize and scale to not saturate when mixing a lot of channels */ + return sample >> (MAD_F_FRACBITS + 2 - 16); +} +#endif + +void MixerChannel::mix(int16 * data, uint32 len) +{ + if (!_sfx_sound) + return; + +#ifdef COMPRESSED_SOUND_FILE + if (type == MIXER_STANDARD) { +#endif + int8 *s; + uint32 fp_pos, fp_speed; + + if (len > sound_data.standard._sfx_size) + len = sound_data.standard._sfx_size; + sound_data.standard._sfx_size -= len; + + s = (int8 *) _sfx_sound + sound_data.standard._sfx_pos; + fp_pos = sound_data.standard._sfx_fp_pos; + fp_speed = sound_data.standard._sfx_fp_speed; + + do { + fp_pos += fp_speed; + *data++ += (*s << 6); + s += fp_pos >> 16; + fp_pos &= 0x0000FFFF; + } while (--len); + + sound_data.standard._sfx_pos = s - (int8 *) _sfx_sound; + sound_data.standard._sfx_fp_speed = fp_speed; + sound_data.standard._sfx_fp_pos = fp_pos; + + if (!sound_data.standard._sfx_size) + clear(); +#ifdef COMPRESSED_SOUND_FILE + } else { + if (type == MIXER_MP3) { + mad_fixed_t const *ch; + while (1) { + ch = + sound_data.mp3.synth.pcm.samples[0] + sound_data.mp3.pos_in_frame; + while ((sound_data.mp3.pos_in_frame < sound_data.mp3.synth.pcm.length) + && (len > 0)) { + if (sound_data.mp3.silence_cut > 0) { + sound_data.mp3.silence_cut--; + } else { + *data++ += scale_sample(*ch++); + len--; + } + sound_data.mp3.pos_in_frame++; + } + if (len == 0) + return; + + if (sound_data.mp3.position >= sound_data.mp3.size) { + clear(); + return; + } + + mad_stream_buffer(&sound_data.mp3.stream, + ((unsigned char *)_sfx_sound) + + sound_data.mp3.position, + sound_data.mp3.size + MAD_BUFFER_GUARD - + sound_data.mp3.position); + + if (mad_frame_decode(&sound_data.mp3.frame, &sound_data.mp3.stream) == + -1) { + /* End of audio... */ + if (sound_data.mp3.stream.error == MAD_ERROR_BUFLEN) { + clear(); + return; + } else if (!MAD_RECOVERABLE(sound_data.mp3.stream.error)) { + error("MAD frame decode error !"); + } + } + mad_synth_frame(&sound_data.mp3.synth, &sound_data.mp3.frame); + sound_data.mp3.pos_in_frame = 0; + sound_data.mp3.position = + (unsigned char *)sound_data.mp3.stream.next_frame - + (unsigned char *)_sfx_sound; + } + } else if (type == MIXER_MP3_CDMUSIC) { + mad_fixed_t const *ch; + mad_timer_t frame_duration; + static long last_pos = 0; + + if (!sound_data.mp3_cdmusic.playing) + return; + + while (1) { + + // See if we just skipped + if (ftell(sound_data.mp3_cdmusic.file) != last_pos) { + int skip_loop; + + // Read the new data + memset(_sfx_sound, 0, + sound_data.mp3_cdmusic.buffer_size + MAD_BUFFER_GUARD); + sound_data.mp3_cdmusic.size = + fread(_sfx_sound, 1, sound_data.mp3_cdmusic.buffer_size, + sound_data.mp3_cdmusic.file); + if (!sound_data.mp3_cdmusic.size) { + sound_data.mp3_cdmusic.playing = false; + return; + } + last_pos = ftell(sound_data.mp3_cdmusic.file); + // Resync + mad_stream_buffer(&sound_data.mp3_cdmusic.stream, + (unsigned char *)_sfx_sound, + sound_data.mp3_cdmusic.size); + skip_loop = 2; + while (skip_loop != 0) { + if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, + &sound_data.mp3_cdmusic.stream) == 0) { + /* Do not decrease duration - see if it's a problem */ + skip_loop--; + if (skip_loop == 0) { + mad_synth_frame(&sound_data.mp3_cdmusic.synth, + &sound_data.mp3_cdmusic.frame); + } + } else { + if (!MAD_RECOVERABLE(sound_data.mp3_cdmusic.stream.error)) { + debug(1, "Unrecoverable error while skipping !"); + sound_data.mp3_cdmusic.playing = false; + return; + } + } + } + // We are supposed to be in synch + mad_frame_mute(&sound_data.mp3_cdmusic.frame); + mad_synth_mute(&sound_data.mp3_cdmusic.synth); + // Resume decoding + if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, + &sound_data.mp3_cdmusic.stream) == 0) { + sound_data.mp3_cdmusic.position = + (unsigned char *)sound_data.mp3_cdmusic.stream.next_frame - + (unsigned char *)_sfx_sound; + sound_data.mp3_cdmusic.pos_in_frame = 0; + } else { + sound_data.mp3_cdmusic.playing = false; + return; + } + } + // Get samples, play samples ... + + ch = sound_data.mp3_cdmusic.synth.pcm.samples[0] + + sound_data.mp3_cdmusic.pos_in_frame; + while ((sound_data.mp3_cdmusic.pos_in_frame < + sound_data.mp3_cdmusic.synth.pcm.length) && (len > 0)) { + *data++ += scale_sample(*ch++); + len--; + sound_data.mp3_cdmusic.pos_in_frame++; + } + if (len == 0) { + return; + } + // See if we have finished + // May be incorrect to check the size at the end of a frame but I suppose + // they are short enough :) + + frame_duration = sound_data.mp3_cdmusic.frame.header.duration; + + mad_timer_negate(&frame_duration); + mad_timer_add(&sound_data.mp3_cdmusic.duration, frame_duration); + if (mad_timer_compare(sound_data.mp3_cdmusic.duration, mad_timer_zero) + < 0) { + sound_data.mp3_cdmusic.playing = false; + } + + if (mad_frame_decode(&sound_data.mp3_cdmusic.frame, + &sound_data.mp3_cdmusic.stream) == -1) { + + if (sound_data.mp3_cdmusic.stream.error == MAD_ERROR_BUFLEN) { + int not_decoded; + + if (!sound_data.mp3_cdmusic.stream.next_frame) { + memset(_sfx_sound, 0, + sound_data.mp3_cdmusic.buffer_size + MAD_BUFFER_GUARD); + sound_data.mp3_cdmusic.size = + fread(_sfx_sound, 1, sound_data.mp3_cdmusic.buffer_size, + sound_data.mp3_cdmusic.file); + sound_data.mp3_cdmusic.position = 0; + not_decoded = 0; + } else { + not_decoded = sound_data.mp3_cdmusic.stream.bufend - + sound_data.mp3_cdmusic.stream.next_frame; + memcpy(_sfx_sound, sound_data.mp3_cdmusic.stream.next_frame, + not_decoded); + + sound_data.mp3_cdmusic.size = + fread((unsigned char *)_sfx_sound + not_decoded, 1, + sound_data.mp3_cdmusic.buffer_size - not_decoded, + sound_data.mp3_cdmusic.file); + } + last_pos = ftell(sound_data.mp3_cdmusic.file); + sound_data.mp3_cdmusic.stream.error = MAD_ERROR_NONE; + // Restream + mad_stream_buffer(&sound_data.mp3_cdmusic.stream, + (unsigned char *)_sfx_sound, + sound_data.mp3_cdmusic.size + not_decoded); + if (mad_frame_decode + (&sound_data.mp3_cdmusic.frame, + &sound_data.mp3_cdmusic.stream) == -1) { + debug(1, "Error decoding after restream %d !", + sound_data.mp3.stream.error); + } + } else if (!MAD_RECOVERABLE(sound_data.mp3.stream.error)) { + error("MAD frame decode error in MP3 CDMUSIC !"); + } + } + + mad_synth_frame(&sound_data.mp3_cdmusic.synth, + &sound_data.mp3_cdmusic.frame); + sound_data.mp3_cdmusic.pos_in_frame = 0; + sound_data.mp3_cdmusic.position = + (unsigned char *)sound_data.mp3_cdmusic.stream.next_frame - + (unsigned char *)_sfx_sound; + } + } + } +#endif +} + +void MixerChannel::clear() +{ + free(_sfx_sound); + _sfx_sound = NULL; + +#ifdef COMPRESSED_SOUND_FILE + if (type == MIXER_MP3) { + mad_synth_finish(&sound_data.mp3.synth); + mad_frame_finish(&sound_data.mp3.frame); + mad_stream_finish(&sound_data.mp3.stream); + } +#endif +} + +#endif + + diff --git a/sound/mixer.h b/sound/mixer.h new file mode 100644 index 00000000000..e2002a9e876 --- /dev/null +++ b/sound/mixer.h @@ -0,0 +1,157 @@ +#ifndef _mixer_h_included +#define _mixer_h_included + +typedef uint32 PlayingSoundHandle; + +class SoundMixer { +private: + class Channel { + public: + virtual void mix(int16 *data, uint len) = 0; + virtual void destroy() = 0; + }; + + class Channel_RAW : public Channel { + SoundMixer *_mixer; + void *_ptr; + uint32 _pos; + uint32 _size; + uint32 _fp_speed; + uint32 _fp_pos; + byte _flags; + + + public: + void mix(int16 *data, uint len); + void destroy(); + + Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags); + }; + +#ifdef COMPRESSED_SOUND_FILE + + class Channel_RAW : public Channel { + SoundMixer *_mixer; + + public: + void mix(int16 *data, uint len); + void destroy(); + + Channel_MP3(SoundMixer *mixer, void *sound, uint rate); + }; + +#endif + + static void on_generate_samples(void *s, byte *samples, int len); + +public: + typedef void PremixProc(void *param, int16 *data, uint len); + + uint _output_rate; + + int16 *_volume_table; + + enum { + NUM_CHANNELS = 16, + }; + + void *_premix_param; + PremixProc *_premix_proc; + + Channel *_channels[NUM_CHANNELS]; + PlayingSoundHandle *_handles[NUM_CHANNELS]; + + void insert(PlayingSoundHandle *handle, Channel *chan); + void uninsert(Channel *chan); + + /* start playing a raw sound */ + enum { + FLAG_AUTOFREE = 1, + FLAG_UNSIGNED = 2, /* unsigned samples */ + FLAG_FILE = 4, /* sound is a FILE * that's read from */ + }; + void play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags); + + /* Premix procedure, useful when using fmopl adlib */ + void setup_premix(void *param, PremixProc *proc); + + /* mix */ + void mix(int16 *buf, uint len); + + /* stop all currently playing sounds */ + void stop_all(); + + /* stop playing a specific sound */ + void stop(PlayingSoundHandle psh); + + /* is any channel active? */ + bool has_active_channel(); + + /* bind to the OSystem object => mixer will be + * invoked automatically when samples need + * to be generated */ + void bind_to_system(OSystem *syst); + + /* set the volume, 0-256 */ + void set_volume(int volume); + +}; + + +struct MP3OffsetTable { /* Compressed Sound (.SO3) */ + int org_offset; + int new_offset; + int num_tags; + int compressed_size; +}; + + + +#if 0 +typedef enum { /* Mixer types */ + MIXER_STANDARD, + MIXER_MP3, + MIXER_MP3_CDMUSIC +} MixerType; + +struct MixerChannel { /* Mixer Channel */ + void *_sfx_sound; + MixerType type; + union { + struct { + uint32 _sfx_pos; + uint32 _sfx_size; + uint32 _sfx_fp_speed; + uint32 _sfx_fp_pos; + } standard; +#ifdef COMPRESSED_SOUND_FILE + struct { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + uint32 silence_cut; + uint32 pos_in_frame; + uint32 position; + uint32 size; + } mp3; + struct { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + uint32 pos_in_frame; + uint32 position; + uint32 size; + uint32 buffer_size; + mad_timer_t duration; + bool playing; + FILE *file; + } mp3_cdmusic; +#endif + } sound_data; + void mix(int16 *data, uint32 len); + void clear(); +}; +#endif + + +#endif /* _mixer_h_included */ diff --git a/system.h b/system.h index 69f4a9ee49f..8bfd7a85c00 100644 --- a/system.h +++ b/system.h @@ -3,7 +3,7 @@ class OSystem { public: typedef int ThreadProc(void *param); - typedef void SoundProc(void *param, int16 *buf, int len); + typedef void SoundProc(void *param, byte *buf, int len); struct Event { int event_code; @@ -34,17 +34,17 @@ public: }; enum { - PARAM_TOGGLE_FULLSCREEN = 1, - PARAM_WINDOW_CAPTION = 2, - PARAM_OPEN_CD = 3, - PARAM_HOTSWAP_GFX_MODE = 4, - PARAM_SHOW_DEFAULT_CURSOR = 5, + PROP_TOGGLE_FULLSCREEN = 1, + PROP_SET_WINDOW_CAPTION = 2, + PROP_OPEN_CD = 3, + PROP_SET_GFX_MODE = 4, + PROP_SHOW_DEFAULT_CURSOR = 5, + PROP_GET_SAMPLE_RATE = 6, }; enum { - SOUND_NONE = 0, - SOUND_8BIT = 1, - SOUND_16BIT = 2, + SOUND_8BIT = 0, + SOUND_16BIT = 1, }; // Set colors of the palette @@ -52,7 +52,7 @@ public: // Set the size of the video bitmap. // Typically, 320x200 - virtual void init_size(uint w, uint h, byte sound) = 0; + virtual void init_size(uint w, uint h) = 0; // Draw a bitmap to screen. // The screen will not be updated to reflect the new bitmap @@ -87,9 +87,12 @@ public: virtual bool poll_event(Event *event) = 0; // Set the function to be invoked whenever samples need to be generated - virtual void set_sound_proc(void *param, SoundProc *proc) = 0; + // Format is the sample type format. + // Only 16-bit signed mode is needed for simon & scumm + virtual void set_sound_proc(void *param, SoundProc *proc, byte format) = 0; - virtual uint32 set_param(int param, uint32 value) = 0; + // Get or set a property + virtual uint32 property(int param, uint32 value) = 0; // Quit virtual void quit() = 0; diff --git a/wince/pocketpc.cpp b/wince/pocketpc.cpp index 698cf47de86..2cd7953ad48 100644 --- a/wince/pocketpc.cpp +++ b/wince/pocketpc.cpp @@ -155,7 +155,7 @@ Scumm scumm; ScummDebugger debugger; Gui gui; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; @@ -953,7 +953,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLin int argc = 3; char* argv[3]; char argdir[MAX_PATH]; - SoundEngine *se; + IMuse *se; sound_activated = true; hide_toolbar = false; @@ -984,7 +984,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLin keypad_init(); registry_init(); - se = (SoundEngine*)scumm._soundEngine; + se = scumm._imuse; se->set_music_volume(scumm._sound_volume_music); se->set_master_volume(scumm._sound_volume_master); diff --git a/windows.cpp b/windows.cpp index 1265842b766..6e4037409a8 100644 --- a/windows.cpp +++ b/windows.cpp @@ -22,7 +22,6 @@ #include #include "scumm.h" -#include "sound.h" #include "cdmusic.h" #include "gui.h" @@ -108,7 +107,7 @@ int sel; Scumm scumm; ScummDebugger debugger; Gui gui; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; WndMan wm[1]; diff --git a/x11.cpp b/x11.cpp index d2e9928bc09..3d249ac2a1c 100644 --- a/x11.cpp +++ b/x11.cpp @@ -24,7 +24,6 @@ #include "stdafx.h" #include "scumm.h" #include "gui.h" -#include "sound.h" #include "cdmusic.h" #include "mp3_cd.h" @@ -50,7 +49,7 @@ Scumm scumm; ScummDebugger debugger; Gui gui; -SoundEngine sound; +IMuse sound; SOUND_DRIVER_TYPE snd_driv; static unsigned char *local_fb;