wrote new mixer class,
cleaned up sound header files, integrated mixer into scummvm & simon svn-id: r3937
This commit is contained in:
parent
a5e3dbb85d
commit
ac62a7cb2e
32 changed files with 2917 additions and 2661 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
2
gfx.cpp
2
gfx.cpp
|
@ -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);
|
||||||
|
|
9
gui.cpp
9
gui.cpp
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
3
main.cpp
3
main.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
17
scumm.h
|
@ -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];
|
||||||
|
|
||||||
|
|
38
scummvm.cpp
38
scummvm.cpp
|
@ -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;
|
||||||
|
|
32
scummvm.dsp
32
scummvm.dsp
|
@ -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
75
sdl.cpp
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
392
sound.cpp
|
@ -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
645
sound.h
|
@ -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
|
|
989
sound/adlib.cpp
989
sound/adlib.cpp
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
314
sound/gmidi.cpp
314
sound/gmidi.cpp
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
2083
sound/imuse.cpp
2083
sound/imuse.cpp
File diff suppressed because it is too large
Load diff
46
sound/imuse.h
Normal file
46
sound/imuse.h
Normal 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); }
|
||||||
|
};
|
|
@ -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 */
|
|
@ -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
491
sound/mixer.cpp
Normal 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
157
sound/mixer.h
Normal 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 */
|
27
system.h
27
system.h
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
3
x11.cpp
3
x11.cpp
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue