wrote new mixer class,

cleaned up sound header files,
integrated mixer into scummvm & simon

svn-id: r3937
This commit is contained in:
Ludvig Strigeus 2002-04-14 18:13:08 +00:00
parent a5e3dbb85d
commit ac62a7cb2e
32 changed files with 2917 additions and 2661 deletions

View file

@ -23,7 +23,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "gui.h" #include "gui.h"
#include "sound.h"
#include "dc.h" #include "dc.h"
#include "icon.h" #include "icon.h"
@ -33,7 +32,7 @@ ScummDebugger debugger;
Gui gui; Gui gui;
Icon icon; Icon icon;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
/* CD Audio stubs */ /* CD Audio stubs */

View file

@ -23,8 +23,9 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "gameDetector.h" #include "gameDetector.h"
#include "imuse.h"
static const char USAGE_STRING[] = static const char USAGE_STRING[] =
@ -104,17 +105,11 @@ void GameDetector::parseCommandLine(int argc, char **argv)
case 'm':{ case 'm':{
if (*(s + 1) == '\0') if (*(s + 1) == '\0')
goto ShowHelpAndExit; goto ShowHelpAndExit;
SoundEngine *se = (SoundEngine *)_soundEngine; _music_volume = atoi(s + 1);
if (se)
se->set_music_volume(atoi(s + 1));
goto NextArg; goto NextArg;
} }
case 'r':{ case 'r':{
SoundEngine *se = (SoundEngine *)_soundEngine; _mt32emulate = true;
if (se)
se->_mt32emulate = true;
break; break;
} }
case 'e': case 'e':
@ -208,8 +203,8 @@ bool GameDetector::parseMusicDriver(const char *s) {
for(i=0; i!=ARRAYSIZE(music_drivers); i++,md++) { for(i=0; i!=ARRAYSIZE(music_drivers); i++,md++) {
if (!scumm_stricmp(md->name, s)) { if (!scumm_stricmp(md->name, s)) {
/* FIXME: when adlib driver is in use, propagate that to /* FIXME: when adlib driver is in use, propagate that to
* the Scumm class, and let it create an AdlibSoundDriver * the IMuse class, and let it create an IMuseAdlib driver
* instead of MidiSoundDriver */ * instead of IMuseGM driver */
if (md->id == -1) { if (md->id == -1) {
_use_adlib = true; _use_adlib = true;
} }

View file

@ -34,6 +34,9 @@ public:
bool _use_adlib; bool _use_adlib;
byte _music_volume;
bool _mt32emulate;
uint16 _debugMode; uint16 _debugMode;
uint16 _noSubtitles; uint16 _noSubtitles;
uint16 _bootParam; uint16 _bootParam;
@ -41,7 +44,6 @@ public:
char *_gameDataPath; char *_gameDataPath;
int _gameTempo; int _gameTempo;
void *_soundEngine;
int _midi_driver; int _midi_driver;
char *_exe_name; char *_exe_name;
const char *_gameText; const char *_gameText;

View file

@ -584,7 +584,7 @@ void Scumm::unkVirtScreen4(int a)
//setDirtyRange(0, 0, vs->height); //setDirtyRange(0, 0, vs->height);
//updateDirtyScreen(0); //updateDirtyScreen(0);
/* XXX: EGA_proc4(0); */ /* XXX: EGA_proc4(0); */
warning("EGA_proc4"); /* FIXME */ // warning("EGA_proc4"); /* FIXME */
break; break;
case 134: case 134:
unkScreenEffect5(0); unkScreenEffect5(0);

View file

@ -21,8 +21,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "gui.h" #include "gui.h"
#include "guimaps.h" #include "guimaps.h"
#include "imuse.h"
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
// Additional variables for Win32 specific GUI // Additional variables for Win32 specific GUI
@ -484,12 +486,13 @@ void Gui::handleSoundDialogCommand(int cmd)
{ {
if (cmd == 40 || cmd == 50) { if (cmd == 40 || cmd == 50) {
if (cmd == 40) { if (cmd == 40) {
SoundEngine *se = (SoundEngine *)_s->_soundEngine;
_s->_sound_volume_master = _gui_variables[0]; // Master _s->_sound_volume_master = _gui_variables[0]; // Master
_s->_sound_volume_music = _gui_variables[1]; // Music _s->_sound_volume_music = _gui_variables[1]; // Music
_s->_sound_volume_sfx = _gui_variables[2]; // SFX _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(); registry_save();
} }

View file

@ -31,7 +31,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "gui.h" #include "gui.h"
#include "sound.h"
#include "cdmusic.h" #include "cdmusic.h"
#include "mp3_cd.h" #include "mp3_cd.h"
#include "gameDetector.h" #include "gameDetector.h"
@ -138,7 +137,7 @@ int sel;
Scumm *scumm; Scumm *scumm;
ScummDebugger debugger; ScummDebugger debugger;
Gui gui; Gui gui;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
OSystem _system; OSystem _system;
GameDetector detector; GameDetector detector;
@ -1025,7 +1024,6 @@ void InitScummStuff()
scumm->_scale = detector._scale; scumm->_scale = detector._scale;
scumm->_gameDataPath = detector._gameDataPath; scumm->_gameDataPath = detector._gameDataPath;
scumm->_gameTempo = detector._gameTempo; scumm->_gameTempo = detector._gameTempo;
scumm->_soundEngine = detector._soundEngine;
scumm->_videoMode = detector._videoMode; scumm->_videoMode = detector._videoMode;
scumm->_exe_name = detector._exe_name; scumm->_exe_name = detector._exe_name;
scumm->_gameId = detector._gameId; scumm->_gameId = detector._gameId;

View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "gameDetector.h" #include "gameDetector.h"
#include "gui.h" #include "gui.h"
#include "simon/simon.h" #include "simon/simon.h"
@ -57,7 +58,7 @@ int main(int argc, char *argv[])
{ {
char *s = detector.getGameName(); char *s = detector.getGameName();
system->set_param(OSystem::PARAM_WINDOW_CAPTION, (long)s); system->property(OSystem::PROP_SET_WINDOW_CAPTION, (long)s);
free(s); free(s);
} }

View file

@ -64,7 +64,7 @@ Gui gui;
OSystem _system; OSystem _system;
GameDetector detector; GameDetector detector;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
typedef void (*ScalerFunc)( uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height ); 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->_scale = detector._scale;
scumm->_gameDataPath = detector._gameDataPath; scumm->_gameDataPath = detector._gameDataPath;
scumm->_gameTempo = detector._gameTempo; scumm->_gameTempo = detector._gameTempo;
scumm->_soundEngine = detector._soundEngine;
scumm->_videoMode = detector._videoMode; scumm->_videoMode = detector._videoMode;
scumm->_exe_name = detector._exe_name; scumm->_exe_name = detector._exe_name;
scumm->_gameId = detector._gameId; scumm->_gameId = detector._gameId;

View file

@ -40,7 +40,7 @@
extern int GetTicks(); extern int GetTicks();
extern Scumm scumm; extern Scumm scumm;
extern SoundEngine sound; extern IMuse sound;
extern SOUND_DRIVER_TYPE snd_driv; extern SOUND_DRIVER_TYPE snd_driv;
#define AHI_BUF_SIZE (8*1024) #define AHI_BUF_SIZE (8*1024)

View file

@ -22,6 +22,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "imuse.h"
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
#define _MANAGE_OLD_SAVE #define _MANAGE_OLD_SAVE
@ -742,9 +744,8 @@ void Scumm::saveOrLoad(Serializer * s)
} }
} }
if (_soundEngine) if (_imuse)
((SoundEngine *)_soundEngine)->save_or_load(s); _imuse->save_or_load(s, this);
} }
void Scumm::saveLoadResource(Serializer * ser, int type, int idx) void Scumm::saveLoadResource(Serializer * ser, int type, int idx)

17
scumm.h
View file

@ -21,6 +21,7 @@
#include "scummsys.h" #include "scummsys.h"
#include "system.h" #include "system.h"
#include "mixer.h"
#ifdef COMPRESSED_SOUND_FILE #ifdef COMPRESSED_SOUND_FILE
#include <mad.h> #include <mad.h>
@ -35,6 +36,7 @@
class GameDetector; class GameDetector;
class Gui; class Gui;
class Scumm; class Scumm;
class IMuse;
struct Actor; struct Actor;
struct ScummDebugger; struct ScummDebugger;
struct Serializer; struct Serializer;
@ -549,7 +551,6 @@ enum MouseButtonStatus {
#include "gfx.h" #include "gfx.h"
#include "boxes.h" #include "boxes.h"
#include "sound.h"
#include "akos.h" #include "akos.h"
#include "smush.h" #include "smush.h"
@ -559,7 +560,7 @@ public:
* That results in a shorter form of the opcode * That results in a shorter form of the opcode
* on some architectures. */ * on some architectures. */
OSystem *_system; OSystem *_system;
void *_soundEngine; IMuse *_imuse;
Gui *_gui; Gui *_gui;
uint32 _features; uint32 _features;
VerbSlot *_verbs; VerbSlot *_verbs;
@ -939,10 +940,10 @@ public:
void runVerbCode(int script, int entry, int a, int b, int16 *vars); void runVerbCode(int script, int entry, int a, int b, int16 *vars);
void setVerbObject(uint room, uint object, uint verb); void setVerbObject(uint room, uint object, uint verb);
/* Should be in Sound class */ /* Should be in Sound class */
MixerChannel _mixer_channel[NUM_MIXER]; SoundMixer _mixer[1];
int _gameTempo;
// MixerChannel _mixer_channel[NUM_MIXER];
byte _sfxMode; byte _sfxMode;
bool _use_adlib; bool _use_adlib;
int16 _sound_volume_master, _sound_volume_music, _sound_volume_sfx; int16 _sound_volume_master, _sound_volume_music, _sound_volume_sfx;
@ -982,13 +983,11 @@ public:
int num_sound_effects; // SO3 MP3 compressed audio int num_sound_effects; // SO3 MP3 compressed audio
void pauseSounds(bool pause); void pauseSounds(bool pause);
MixerChannel *allocateMixer();
bool isSfxFinished(); bool isSfxFinished();
void playBundleSound(char *sound); void playBundleSound(char *sound);
void playSfxSound(void *sound, uint32 size, uint rate); 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 stopSfxSound();
void mixWaves(int16 *sounds, int len);
bool _useTalkAnims; bool _useTalkAnims;
uint16 _defaultTalkDelay; uint16 _defaultTalkDelay;
@ -1682,7 +1681,6 @@ public:
void updateCursor(); void updateCursor();
void animateCursor(); void animateCursor();
void updatePalette(); void updatePalette();
static void on_generate_samples(void *s, int16 *samples, int len);
}; };
class Scumm_v3 : public Scumm class Scumm_v3 : public Scumm
@ -1798,6 +1796,7 @@ struct Serializer {
}; };
extern const uint32 IMxx_tags[]; extern const uint32 IMxx_tags[];
extern const byte default_scale_table[768]; extern const byte default_scale_table[768];

View file

@ -22,6 +22,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "imuse.h"
#include "gui.h" #include "gui.h"
#include "string.h" #include "string.h"
#include "gameDetector.h" #include "gameDetector.h"
@ -1259,10 +1261,6 @@ void Scumm::launch()
// _scummTimer = 0; // _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::createFromDetector(GameDetector *detector, OSystem *syst)
{ {
Scumm *scumm; Scumm *scumm;
@ -1281,17 +1279,18 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst)
scumm->_system = syst; scumm->_system = syst;
/* This initializes SDL */ /* This initializes SDL */
syst->init_size(320,200, OSystem::SOUND_16BIT); syst->init_size(320,200);
syst->set_param(OSystem::PARAM_OPEN_CD, detector->_cdrom); 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->_fullScreen = detector->_fullScreen;
scumm->_debugMode = detector->_debugMode; scumm->_debugMode = detector->_debugMode;
scumm->_bootParam = detector->_bootParam; scumm->_bootParam = detector->_bootParam;
scumm->_gameDataPath = detector->_gameDataPath; scumm->_gameDataPath = detector->_gameDataPath;
scumm->_gameTempo = detector->_gameTempo;
scumm->_soundEngine = detector->_soundEngine;
scumm->_exe_name = detector->_exe_name; scumm->_exe_name = detector->_exe_name;
scumm->_gameId = detector->_gameId; scumm->_gameId = detector->_gameId;
scumm->_gameText = detector->_gameText; scumm->_gameText = detector->_gameText;
@ -1301,20 +1300,21 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst)
scumm->_cdrom = detector->_cdrom; scumm->_cdrom = detector->_cdrom;
{ {
SoundDriver *sdriv; IMuse *imuse;
SoundEngine *seng;
scumm->_use_adlib = detector->_use_adlib; scumm->_use_adlib = detector->_use_adlib;
if (!detector->_use_adlib) { if (detector->_use_adlib) {
MidiDriver *midi = detector->createMidi(); imuse = IMuse::create_adlib(syst, scumm->_mixer);
sdriv = new MidiSoundDriver;
((MidiSoundDriver*)sdriv)->midiSetDriver(midi);
} else { } 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; scumm->delta = 6;

View file

@ -121,28 +121,32 @@ LINK32=link.exe
# PROP Default_Filter "" # PROP Default_Filter ""
# Begin Source File # Begin Source File
SOURCE=.\sound\adlib.cpp
# End Source File
# Begin Source File
SOURCE=.\sound\fmopl.cpp SOURCE=.\sound\fmopl.cpp
# End Source File # End Source File
# Begin 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 SOURCE=.\sound\imuse.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\sound\imuse.h
# End Source File
# Begin Source File
SOURCE=.\sound\mididrv.cpp SOURCE=.\sound\mididrv.cpp
# End Source File # 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 # End Group
# Begin Group "v3" # Begin Group "v3"
@ -512,10 +516,6 @@ SOURCE=.\smush.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\sound.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h SOURCE=.\StdAfx.h
# End Source File # End Source File
# Begin Source File # Begin Source File

75
sdl.cpp
View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "SDL_thread.h" #include "SDL_thread.h"
#include "gameDetector.h" #include "gameDetector.h"
@ -16,7 +17,7 @@ public:
// Set the size of the video bitmap. // Set the size of the video bitmap.
// Typically, 320x200 // Typically, 320x200
void init_size(uint w, uint h, byte sound); void init_size(uint w, uint h);
// Draw a bitmap to screen. // Draw a bitmap to screen.
// The screen will not be updated to reflect the new bitmap // The screen will not be updated to reflect the new bitmap
@ -51,13 +52,13 @@ public:
bool poll_event(Event *event); bool poll_event(Event *event);
// Set function that generates samples // Set function that generates samples
void set_sound_proc(void *param, SoundProc *proc); void set_sound_proc(void *param, SoundProc *proc, byte sound);
// Quit // Quit
void quit(); void quit();
// Set a parameter // 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); static OSystem *create(int gfx_mode, bool full_screen);
@ -108,9 +109,6 @@ private:
int scaling; int scaling;
SoundProc *_sound_proc;
void *_sound_param;
struct MousePos { struct MousePos {
int16 x,y,w,h; 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); 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() { void OSystem_SDL::load_gfx_mode() {
force_full = true; force_full = true;
scaling = 1; scaling = 1;
@ -307,24 +297,10 @@ void OSystem_SDL::unload_gfx_mode() {
} }
} }
void OSystem_SDL::init_size(uint w, uint h, byte sound) { void OSystem_SDL::init_size(uint w, uint h) {
SDL_AudioSpec desired;
if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT)
error("320x200 is the only game resolution supported"); 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 /* allocate palette, it needs to be persistent across
* driver changes, so i'll alloc it here */ * driver changes, so i'll alloc it here */
_cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256); _cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256);
@ -668,7 +644,7 @@ bool OSystem_SDL::poll_event(Event *event) {
/* internal keypress? */ /* internal keypress? */
if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) { if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) {
set_param(PARAM_TOGGLE_FULLSCREEN, 0); property(PROP_TOGGLE_FULLSCREEN, 0);
break; break;
} }
@ -679,7 +655,7 @@ bool OSystem_SDL::poll_event(Event *event) {
if (b == (KBD_CTRL|KBD_ALT) && if (b == (KBD_CTRL|KBD_ALT) &&
ev.key.keysym.sym>='1' && ev.key.keysym.sym<='6') { 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; break;
} }
@ -733,9 +709,19 @@ bool OSystem_SDL::poll_event(Event *event) {
} }
} }
void OSystem_SDL::set_sound_proc(void *param, SoundProc *proc) { void OSystem_SDL::set_sound_proc(void *param, SoundProc *proc, byte format) {
_sound_proc = proc; SDL_AudioSpec desired;
_sound_param = param;
/* 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(); OSystem_SDL::update_screen();
} }
uint32 OSystem_SDL::set_param(int param, uint32 value) { uint32 OSystem_SDL::property(int param, uint32 value) {
switch(param) { switch(param) {
case PARAM_TOGGLE_FULLSCREEN: case PROP_TOGGLE_FULLSCREEN:
_full_screen ^= true; _full_screen ^= true;
if (!SDL_WM_ToggleFullScreen(sdl_hwscreen)) { if (!SDL_WM_ToggleFullScreen(sdl_hwscreen)) {
@ -818,11 +804,11 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) {
} }
return 1; return 1;
case PARAM_WINDOW_CAPTION: case PROP_SET_WINDOW_CAPTION:
SDL_WM_SetCaption((char*)value, (char*)value); SDL_WM_SetCaption((char*)value, (char*)value);
return 1; return 1;
case PARAM_OPEN_CD: case PROP_OPEN_CD:
if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1)
cdrom = NULL; cdrom = NULL;
else { else {
@ -834,7 +820,7 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) {
} }
break; break;
case PARAM_HOTSWAP_GFX_MODE: case PROP_SET_GFX_MODE:
if (value >= 6) if (value >= 6)
return 0; return 0;
@ -843,9 +829,12 @@ uint32 OSystem_SDL::set_param(int param, uint32 value) {
return 1; return 1;
case PARAM_SHOW_DEFAULT_CURSOR: case PROP_SHOW_DEFAULT_CURSOR:
SDL_ShowCursor(value ? SDL_ENABLE : SDL_DISABLE); SDL_ShowCursor(value ? SDL_ENABLE : SDL_DISABLE);
break; break;
case PROP_GET_SAMPLE_RATE:
return SAMPLES_PER_SEC;
} }
return 0; return 0;
@ -1027,7 +1016,7 @@ void OSystem_SDL::undraw_mouse() {
class OSystem_NULL : public OSystem { class OSystem_NULL : public OSystem {
public: public:
void set_palette(const byte *colors, uint start, uint num) {} 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 copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) {}
void update_screen() {} void update_screen() {}
bool show_mouse(bool visible) { return false; } bool show_mouse(bool visible) { return false; }
@ -1038,9 +1027,9 @@ public:
void delay_msecs(uint msecs); void delay_msecs(uint msecs);
void *create_thread(ThreadProc *proc, void *param) { return NULL; } void *create_thread(ThreadProc *proc, void *param) { return NULL; }
bool poll_event(Event *event) { return false; } 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); } 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); static OSystem *create(int gfx_mode, bool full_screen);
private: private:

View file

@ -23,7 +23,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "scummsys.h" #include "scummsys.h"
#include "system.h" #include "system.h"
#include "gmidi.h" #include "mididrv.h"
#include "mixer.h"
#include "simon.h" #include "simon.h"
void MidiPlayer::read_from_file(void *dst, uint size) { void MidiPlayer::read_from_file(void *dst, uint size) {

View file

@ -23,8 +23,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "scummsys.h" #include "scummsys.h"
#include "system.h" #include "system.h"
#include "mixer.h"
#include "simon.h" #include "simon.h"
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#ifdef WIN32 #ifdef WIN32
@ -5034,8 +5036,7 @@ void SimonState::vc_29_stop_all_sounds() {
/* XXX: implement */ /* XXX: implement */
// warning("vc_29_stop_all_sounds unimplemented"); // warning("vc_29_stop_all_sounds unimplemented");
_voice_size = 0; _mixer->stop_all();
_sound_size = 0;
} }
void SimonState::vc_30_set_base_delay() { void SimonState::vc_30_set_base_delay() {
@ -6518,7 +6519,7 @@ bool SimonState::vc_59_helper() {
#else #else
if (_voice_file==NULL) if (_voice_file==NULL)
return false; return false;
return _voice_size == 0; return _voice_sound == 0;
#endif #endif
} }
@ -6574,9 +6575,8 @@ void SimonState::readSfxFile(const char *filename) {
rewind(in); rewind(in);
/* if a sound is playing, stop it */ /* stop all sounds */
_sound_size = 0; _mixer->stop_all();
if (_sfx_heap) free(_sfx_heap); if (_sfx_heap) free(_sfx_heap);
@ -6595,10 +6595,6 @@ void SimonState::readSfxFile(const char *filename) {
vc_29_stop_all_sounds(); vc_29_stop_all_sounds();
/* if a sound is playing, stop it */
_sound_size = 0;
if (_sfx_heap) free(_sfx_heap); if (_sfx_heap) free(_sfx_heap);
res = atoi(filename + 6) + gss->SOUND_INDEX_BASE - 1; res = atoi(filename + 6) + gss->SOUND_INDEX_BASE - 1;
@ -7386,7 +7382,7 @@ void SimonState::openGameFile() {
loadIconFile(); loadIconFile();
_system->init_size(320,200,OSystem::SOUND_8BIT); _system->init_size(320,200);
startUp(1); startUp(1);
} }
@ -7411,6 +7407,7 @@ void SimonState::runSubroutine101() {
startUp_helper_2(); startUp_helper_2();
} }
#if 0
void SimonState::generateSound(byte *ptr, int len) { void SimonState::generateSound(byte *ptr, int len) {
uint cur; uint cur;
@ -7438,10 +7435,11 @@ void SimonState::generateSound(byte *ptr, int len) {
_sound_ptr += cur; _sound_ptr += cur;
} }
} }
#endif
static void fill_sound(void *userdata, int16 *stream, int len) { //static void fill_sound(void *userdata, int16 *stream, int len) {
((SimonState*)userdata)->generateSound((byte*)stream, len*2); // ((SimonState*)userdata)->generateSound((byte*)stream, len*2);
} //}
void SimonState::dx_copy_rgn_from_3_to_2(uint b, uint r, uint y, uint x) { void SimonState::dx_copy_rgn_from_3_to_2(uint b, uint r, uint y, uint x) {
byte *dst, *src; byte *dst, *src;
@ -7579,8 +7577,10 @@ void SimonState::go(OSystem *syst, MidiDriver *driver) {
_vga_base_delay = 1; _vga_base_delay = 1;
_vk_t_toggle = true; _vk_t_toggle = true;
_system->set_param(OSystem::PARAM_SHOW_DEFAULT_CURSOR, 1); _system->property(OSystem::PROP_SHOW_DEFAULT_CURSOR, 1);
_system->set_sound_proc(this, fill_sound);
_mixer->bind_to_system(_system);
_mixer->set_volume(256);
while(1) { while(1) {
hitarea_stuff(); hitarea_stuff();
@ -7915,11 +7915,11 @@ void SimonState::playVoice(uint voice) {
// assert(voice < 14496/4); // assert(voice < 14496/4);
_voice_size = 0;
if (_voice_offsets == NULL) if (_voice_offsets == NULL)
return; return;
_mixer->stop(_voice_sound);
fseek(_voice_file, _voice_offsets[voice], SEEK_SET); fseek(_voice_file, _voice_offsets[voice], SEEK_SET);
if (fread(&wave_hdr, sizeof(wave_hdr), 1, _voice_file)!=1 || if (fread(&wave_hdr, sizeof(wave_hdr), 1, _voice_file)!=1 ||
@ -7937,7 +7937,8 @@ void SimonState::playVoice(uint voice) {
return; 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) { if (_game & GAME_WIN) {
byte *p; byte *p;
/* stop any currently playing sound */ _mixer->stop(_playing_sound);
_sound_size = 0;
/* Check if _sfx_heap is NULL */ /* Check if _sfx_heap is NULL */
if (_sfx_heap == NULL) { if (_sfx_heap == NULL) {
@ -7968,8 +7968,7 @@ void SimonState::playSound(uint sound) {
p++; p++;
} }
_sound_ptr = p + 8; _mixer->play_raw(&_playing_sound, p+8,*(uint32*)(p+4),22050,SoundMixer::FLAG_UNSIGNED);
_sound_size = ((uint32*)p)[1];
} else { } else {
warning("playSound(%d)", sound); warning("playSound(%d)", sound);
} }

View file

@ -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 */ /* GFX Settings. Sound & Music only works properly with SIMON1WIN */
@ -504,10 +514,10 @@ public:
uint _invoke_timer_callback; uint _invoke_timer_callback;
uint32 _voice_size; // uint32 _voice_size;
uint32 _sound_size; // uint32 _sound_size;
byte *_sound_ptr; // byte *_sound_ptr;
uint _vga_sprite_changed; uint _vga_sprite_changed;
@ -542,6 +552,8 @@ public:
byte _fcs_data_1[8]; byte _fcs_data_1[8];
bool _fcs_data_2[8]; bool _fcs_data_2[8];
SoundMixer _mixer[1];
ThreeValues _threevalues_1, _threevalues_2, _threevalues_3, _threevalues_4; ThreeValues _threevalues_1, _threevalues_2, _threevalues_3, _threevalues_4;
int _free_string_slot; int _free_string_slot;
@ -574,6 +586,9 @@ public:
int _num_screen_updates; int _num_screen_updates;
int _vga_tick_counter; int _vga_tick_counter;
PlayingSoundHandle _playing_sound;
PlayingSoundHandle _voice_sound;
int _timer_id; int _timer_id;
FILE *_dump_file; FILE *_dump_file;
@ -994,7 +1009,8 @@ public:
void playVoice(uint voice); void playVoice(uint voice);
void playSound(uint sound); void playSound(uint sound);
void generateSound(byte *ptr, int len);
// void generateSound(byte *ptr, int len);
void playMusic(uint music); void playMusic(uint music);

View file

@ -23,6 +23,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "scummsys.h" #include "scummsys.h"
#include "system.h" #include "system.h"
#include "mixer.h"
#include "simon.h" #include "simon.h"
#include <stdarg.h> #include <stdarg.h>

392
sound.cpp
View file

@ -22,6 +22,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "mididrv.h"
#include "imuse.h"
#include "cdmusic.h" #include "cdmusic.h"
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
@ -54,7 +56,7 @@ void Scumm::processSoundQues()
int i, j; int i, j;
int num; int num;
int16 data[16]; int16 data[16];
SoundEngine *se; IMuse *se;
processSfxQueues(); processSfxQueues();
@ -77,7 +79,7 @@ void Scumm::processSoundQues()
data[j] = _soundQue[i + j]; data[j] = _soundQue[i + j];
i += num; i += num;
se = (SoundEngine *)_soundEngine; se = _imuse;
#if 0 #if 0
debug(1, "processSoundQues(%d,%d,%d,%d,%d,%d,%d,%d,%d)", debug(1, "processSoundQues(%d,%d,%d,%d,%d,%d,%d,%d,%d)",
data[0] >> 8, data[0] >> 8,
@ -100,7 +102,7 @@ void Scumm::processSoundQues()
void Scumm::playSound(int sound) void Scumm::playSound(int sound)
{ {
byte *ptr; byte *ptr;
SoundEngine *se = (SoundEngine *)_soundEngine; IMuse *se = _imuse;
ptr = getResourceAddress(rtSound, sound); ptr = getResourceAddress(rtSound, sound);
if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('SOUN')) { if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('SOUN')) {
@ -253,7 +255,7 @@ bool Scumm::isMouthSyncOff(uint pos)
int Scumm::isSoundRunning(int sound) int Scumm::isSoundRunning(int sound)
{ {
SoundEngine *se; IMuse *se;
int i; int i;
if (sound == current_cd_sound) if (sound == current_cd_sound)
@ -271,7 +273,7 @@ int Scumm::isSoundRunning(int sound)
if (!isResourceLoaded(rtSound, sound)) if (!isResourceLoaded(rtSound, sound))
return 0; return 0;
se = (SoundEngine *)_soundEngine; se = _imuse;
if (!se) if (!se)
return 0; return 0;
return se->get_sound_status(sound); return se->get_sound_status(sound);
@ -300,7 +302,7 @@ bool Scumm::isSoundInQueue(int sound)
void Scumm::stopSound(int a) void Scumm::stopSound(int a)
{ {
SoundEngine *se; IMuse *se;
int i; int i;
if (a == current_cd_sound) { if (a == current_cd_sound) {
@ -308,7 +310,7 @@ void Scumm::stopSound(int a)
cd_stop(); cd_stop();
} }
se = (SoundEngine *)_soundEngine; se = _imuse;
if (se) if (se)
se->stop_sound(a); se->stop_sound(a);
@ -319,7 +321,7 @@ void Scumm::stopSound(int a)
void Scumm::stopAllSounds() void Scumm::stopAllSounds()
{ {
SoundEngine *se = (SoundEngine *)_soundEngine; IMuse *se = _imuse;
if (current_cd_sound != 0) { if (current_cd_sound != 0) {
current_cd_sound = 0; current_cd_sound = 0;
@ -376,7 +378,7 @@ void Scumm::talkSound(uint32 a, uint32 b, int mode)
void Scumm::setupSound() void Scumm::setupSound()
{ {
SoundEngine *se = (SoundEngine *)_soundEngine; IMuse *se = _imuse;
if (se) { if (se) {
se->setBase(res.address[rtSound]); se->setBase(res.address[rtSound]);
if (se->get_music_volume() == 0) if (se->get_music_volume() == 0)
@ -392,7 +394,7 @@ void Scumm::setupSound()
void Scumm::pauseSounds(bool pause) void Scumm::pauseSounds(bool pause)
{ {
SoundEngine *se = (SoundEngine *)_soundEngine; IMuse *se = _imuse;
if (se) if (se)
se->pause(pause); se->pause(pause);
_soundsPaused = pause; _soundsPaused = pause;
@ -562,85 +564,17 @@ void *Scumm::openSfxFile()
return file; 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() void Scumm::stopSfxSound()
{ {
MixerChannel *mc = _mixer_channel; _mixer->stop_all();
int i;
for (i = 0; i < NUM_MIXER; i++, mc++) {
if (mc->_sfx_sound)
mc->clear();
}
} }
bool Scumm::isSfxFinished() bool Scumm::isSfxFinished()
{ {
int i; return !_mixer->has_active_channel();
for (i = 0; i < NUM_MIXER; i++)
if (_mixer_channel[i]._sfx_sound)
return false;
return true;
} }
#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) void Scumm::playBundleSound(char *sound)
{ {
warning("playBundleSound: %s", sound); warning("playBundleSound: %s", sound);
@ -648,304 +582,8 @@ void Scumm::playBundleSound(char *sound)
void Scumm::playSfxSound(void *sound, uint32 size, uint rate) void Scumm::playSfxSound(void *sound, uint32 size, uint rate)
{ {
MixerChannel *mc = allocateMixer(); _mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_AUTOFREE);
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
} }
#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));
}

645
sound.h
View file

@ -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

View file

@ -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;
}

View file

@ -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);
}
}

File diff suppressed because it is too large Load diff

46
sound/imuse.h Normal file
View file

@ -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); }
};

View file

@ -30,11 +30,9 @@
#include <devices/timer.h> #include <devices/timer.h>
#endif #endif
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "gmidi.h" #include "mididrv.h"
#ifdef WIN32 #ifdef WIN32
@ -326,9 +324,6 @@ const char *MidiDriver::get_error_name(int error_code) {
#if 0 #if 0
void MidiDriver::midiInit() void MidiDriver::midiInit()
{ {
if (MidiInitialized != true) { if (MidiInitialized != true) {
@ -686,4 +681,51 @@ void MidiDriver::midiInitNull()
warning warning
("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib"); ("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib");
} }
#endif
/* old header stuff.. */
/* General Midi header file */
#define SEQ_MIDIPUTC 5
#define SPECIAL_CHANNEL 9
#define DEVICE_NUM 0
#ifdef __APPLE__CW
#include <QuickTimeComponents.h>
#include "QuickTimeMusic.h"
NoteAllocator qtNoteAllocator;
NoteChannel qtNoteChannel[16];
NoteRequest simpleNoteRequest;
#endif
#ifdef WIN32
#include <winsock.h>
#elif defined(UNIX)
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#ifdef __MORPHOS__
#include <exec/types.h>
#include <devices/amidi.h>
#define NO_PPCINLINE_STDARG
#define NO_PPCINLINE_VARARGS
#include <clib/alib_protos.h>
#include <proto/exec.h>
#undef CMD_INVALID
extern struct IOMidiRequest *ScummMidiRequest;
#endif
#endif /* 0 */

View file

@ -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 { struct MidiEvent {
uint32 delta; uint32 delta;
uint32 event; uint32 event;
@ -105,56 +97,3 @@ MidiDriver *MidiDriver_TIMIDITY_create();
MidiDriver *MidiDriver_SEQ_create(); MidiDriver *MidiDriver_SEQ_create();
MidiDriver *MidiDriver_QT_create(); MidiDriver *MidiDriver_QT_create();
MidiDriver *MidiDriver_AMIDI_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 <QuickTimeComponents.h>
#include "QuickTimeMusic.h"
NoteAllocator qtNoteAllocator;
NoteChannel qtNoteChannel[16];
NoteRequest simpleNoteRequest;
#endif
#ifdef WIN32
#include <winsock.h>
#elif defined(UNIX)
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#ifdef __MORPHOS__
#include <exec/types.h>
#include <devices/amidi.h>
#define NO_PPCINLINE_STDARG
#define NO_PPCINLINE_VARARGS
#include <clib/alib_protos.h>
#include <proto/exec.h>
#undef CMD_INVALID
extern struct IOMidiRequest *ScummMidiRequest;
#endif
#endif /* defined(gmidi_h) */

491
sound/mixer.cpp Normal file
View file

@ -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

157
sound/mixer.h Normal file
View file

@ -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 */

View file

@ -3,7 +3,7 @@
class OSystem { class OSystem {
public: public:
typedef int ThreadProc(void *param); 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 { struct Event {
int event_code; int event_code;
@ -34,17 +34,17 @@ public:
}; };
enum { enum {
PARAM_TOGGLE_FULLSCREEN = 1, PROP_TOGGLE_FULLSCREEN = 1,
PARAM_WINDOW_CAPTION = 2, PROP_SET_WINDOW_CAPTION = 2,
PARAM_OPEN_CD = 3, PROP_OPEN_CD = 3,
PARAM_HOTSWAP_GFX_MODE = 4, PROP_SET_GFX_MODE = 4,
PARAM_SHOW_DEFAULT_CURSOR = 5, PROP_SHOW_DEFAULT_CURSOR = 5,
PROP_GET_SAMPLE_RATE = 6,
}; };
enum { enum {
SOUND_NONE = 0, SOUND_8BIT = 0,
SOUND_8BIT = 1, SOUND_16BIT = 1,
SOUND_16BIT = 2,
}; };
// Set colors of the palette // Set colors of the palette
@ -52,7 +52,7 @@ public:
// Set the size of the video bitmap. // Set the size of the video bitmap.
// Typically, 320x200 // 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. // Draw a bitmap to screen.
// The screen will not be updated to reflect the new bitmap // The screen will not be updated to reflect the new bitmap
@ -87,9 +87,12 @@ public:
virtual bool poll_event(Event *event) = 0; virtual bool poll_event(Event *event) = 0;
// Set the function to be invoked whenever samples need to be generated // 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 // Quit
virtual void quit() = 0; virtual void quit() = 0;

View file

@ -155,7 +155,7 @@ Scumm scumm;
ScummDebugger debugger; ScummDebugger debugger;
Gui gui; Gui gui;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
@ -953,7 +953,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLin
int argc = 3; int argc = 3;
char* argv[3]; char* argv[3];
char argdir[MAX_PATH]; char argdir[MAX_PATH];
SoundEngine *se; IMuse *se;
sound_activated = true; sound_activated = true;
hide_toolbar = false; hide_toolbar = false;
@ -984,7 +984,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLin
keypad_init(); keypad_init();
registry_init(); registry_init();
se = (SoundEngine*)scumm._soundEngine; se = scumm._imuse;
se->set_music_volume(scumm._sound_volume_music); se->set_music_volume(scumm._sound_volume_music);
se->set_master_volume(scumm._sound_volume_master); se->set_master_volume(scumm._sound_volume_master);

View file

@ -22,7 +22,6 @@
#include <assert.h> #include <assert.h>
#include "scumm.h" #include "scumm.h"
#include "sound.h"
#include "cdmusic.h" #include "cdmusic.h"
#include "gui.h" #include "gui.h"
@ -108,7 +107,7 @@ int sel;
Scumm scumm; Scumm scumm;
ScummDebugger debugger; ScummDebugger debugger;
Gui gui; Gui gui;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
WndMan wm[1]; WndMan wm[1];

View file

@ -24,7 +24,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "scumm.h" #include "scumm.h"
#include "gui.h" #include "gui.h"
#include "sound.h"
#include "cdmusic.h" #include "cdmusic.h"
#include "mp3_cd.h" #include "mp3_cd.h"
@ -50,7 +49,7 @@
Scumm scumm; Scumm scumm;
ScummDebugger debugger; ScummDebugger debugger;
Gui gui; Gui gui;
SoundEngine sound; IMuse sound;
SOUND_DRIVER_TYPE snd_driv; SOUND_DRIVER_TYPE snd_driv;
static unsigned char *local_fb; static unsigned char *local_fb;