Some work on the sound module handling and the SB16 midi file output.
- Added the capability to load up to 4 sound drivers and added methods to get pointers to the waveout, wavein and midiout services of a driver. - Rewrite of the SB16 midi file output code. In midimode 2 and 3 the midiout service of the 'file' driver is used. Removed obsolete midi file handling. - Re-implemented the closemidioutput() method to make runtime changes of the midi setup work with the new code.
This commit is contained in:
parent
c8207c7a10
commit
b1e8a6369c
@ -77,13 +77,17 @@ class BOCHSAPI bx_devmodel_c : public logfunctions {
|
||||
#endif
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// declare stubs for PCI devices
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// forward declarations
|
||||
class bx_list_c;
|
||||
class device_image_t;
|
||||
class cdrom_base_c;
|
||||
class bx_soundlow_waveout_c;
|
||||
class bx_soundlow_wavein_c;
|
||||
class bx_soundlow_midiout_c;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// declare stubs for PCI devices
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// the best should be deriving of bx_pci_device_stub_c from bx_devmodel_c
|
||||
// but it make serious problems for cirrus_svga device
|
||||
@ -350,14 +354,14 @@ public:
|
||||
#if BX_SUPPORT_SOUNDLOW
|
||||
class BOCHSAPI bx_soundmod_ctl_stub_c : public bx_devmodel_c {
|
||||
public:
|
||||
virtual void* get_module() {
|
||||
STUBFUNC(soundmod_ctl, get_module); return NULL;
|
||||
virtual bx_soundlow_waveout_c* get_waveout(const char *driver) {
|
||||
STUBFUNC(soundmod_ctl, get_waveout); return NULL;
|
||||
}
|
||||
virtual bx_bool beep_on(float frequency) {
|
||||
return 0;
|
||||
virtual bx_soundlow_wavein_c* get_wavein(const char *driver) {
|
||||
STUBFUNC(soundmod_ctl, get_wavein); return NULL;
|
||||
}
|
||||
virtual bx_bool beep_off() {
|
||||
return 0;
|
||||
virtual bx_soundlow_midiout_c* get_midiout(const char *driver) {
|
||||
STUBFUNC(soundmod_ctl, get_midiout); return NULL;
|
||||
}
|
||||
virtual void VOC_init_file(FILE *stream) {}
|
||||
virtual void VOC_write_block(FILE *stream, int block, Bit32u headerlen,
|
||||
|
@ -186,7 +186,6 @@ bx_es1370_c::bx_es1370_c()
|
||||
memset(&s, 0, sizeof(bx_es1370_t));
|
||||
s.dac1_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
s.dac2_timer_index = BX_NULL_TIMER_HANDLE;
|
||||
soundmod = NULL;
|
||||
waveout = NULL;
|
||||
wavein = NULL;
|
||||
wavefile = NULL;
|
||||
@ -223,9 +222,8 @@ void bx_es1370_c::init(void)
|
||||
|
||||
BX_ES1370_THIS pci_base_address[0] = 0;
|
||||
|
||||
BX_ES1370_THIS soundmod = DEV_sound_get_module();
|
||||
BX_ES1370_THIS waveout = soundmod->get_waveout();
|
||||
BX_ES1370_THIS wavein = soundmod->get_wavein();
|
||||
BX_ES1370_THIS waveout = DEV_sound_get_waveout("default");
|
||||
BX_ES1370_THIS wavein = DEV_sound_get_wavein("default");
|
||||
BX_ES1370_THIS s.dac_outputinit = 1;
|
||||
BX_ES1370_THIS s.adc_inputinit = 0;
|
||||
BX_ES1370_THIS s.dac_nr_active = -1;
|
||||
|
@ -71,7 +71,6 @@ typedef struct {
|
||||
|
||||
|
||||
// forward definitions
|
||||
class bx_sound_lowlevel_c;
|
||||
class bx_soundlow_waveout_c;
|
||||
class bx_soundlow_wavein_c;
|
||||
|
||||
@ -118,7 +117,6 @@ private:
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
|
||||
bx_sound_lowlevel_c *soundmod;
|
||||
bx_soundlow_waveout_c *waveout;
|
||||
bx_soundlow_wavein_c *wavein;
|
||||
int wavemode;
|
||||
|
@ -175,7 +175,6 @@ void CDECL libsb16_LTX_plugin_fini(void)
|
||||
|
||||
// some shortcuts to save typing
|
||||
#define LOGFILE BX_SB16_THIS logfile
|
||||
#define MIDIDATA BX_SB16_THIS midifile
|
||||
#define WAVEDATA BX_SB16_THIS wavefile
|
||||
#define MPU BX_SB16_THIS mpu401
|
||||
#define DSP BX_SB16_THIS dsp
|
||||
@ -183,7 +182,6 @@ void CDECL libsb16_LTX_plugin_fini(void)
|
||||
#define EMUL BX_SB16_THIS emuldata
|
||||
#define OPL BX_SB16_THIS opl
|
||||
|
||||
#define BX_SB16_OUTPUT BX_SB16_THIS soundmod
|
||||
#define BX_SB16_WAVEOUT BX_SB16_THIS waveout
|
||||
#define BX_SB16_WAVEIN BX_SB16_THIS wavein
|
||||
#define BX_SB16_MIDIOUT BX_SB16_THIS midiout
|
||||
@ -191,6 +189,13 @@ void CDECL libsb16_LTX_plugin_fini(void)
|
||||
// here's a safe way to print out null pointeres
|
||||
#define MIGHT_BE_NULL(x) ((x==NULL)? "(null)" : x)
|
||||
|
||||
const char *sb16_midi_drv[4] = {
|
||||
"dummy",
|
||||
"default",
|
||||
"file",
|
||||
"file",
|
||||
};
|
||||
|
||||
// the device object
|
||||
|
||||
bx_sb16_c::bx_sb16_c(void)
|
||||
@ -204,11 +209,10 @@ bx_sb16_c::bx_sb16_c(void)
|
||||
mpu401.timer_handle = BX_NULL_TIMER_HANDLE;
|
||||
dsp.timer_handle = BX_NULL_TIMER_HANDLE;
|
||||
opl.timer_handle = BX_NULL_TIMER_HANDLE;
|
||||
soundmod = NULL;
|
||||
waveout = NULL;
|
||||
wavein = NULL;
|
||||
midiout = NULL;
|
||||
midimode = 0;
|
||||
midifile = NULL;
|
||||
wavemode = 0;
|
||||
wavefile = NULL;
|
||||
loglevel = 0;
|
||||
@ -255,21 +259,19 @@ void bx_sb16_c::init(void)
|
||||
BX_SB16_THIS loglevel = SIM->get_param_num("loglevel", base)->get();
|
||||
|
||||
// always initialize lowlevel driver
|
||||
BX_SB16_OUTPUT = DEV_sound_get_module();
|
||||
if (BX_SB16_OUTPUT == NULL) {
|
||||
BX_PANIC(("Couldn't initialize lowlevel driver"));
|
||||
}
|
||||
BX_SB16_WAVEOUT = soundmod->get_waveout();
|
||||
BX_SB16_WAVEOUT = DEV_sound_get_waveout("default");
|
||||
if (BX_SB16_WAVEOUT == NULL) {
|
||||
BX_PANIC(("Couldn't initialize lowlevel driver (waveout)"));
|
||||
BX_PANIC(("Couldn't initialize waveout driver"));
|
||||
}
|
||||
BX_SB16_WAVEIN = soundmod->get_wavein();
|
||||
BX_SB16_WAVEIN = DEV_sound_get_wavein("default");
|
||||
if (BX_SB16_WAVEIN == NULL) {
|
||||
BX_PANIC(("Couldn't initialize lowlevel driver (wavein)"));
|
||||
BX_PANIC(("Couldn't initialize wavein driver"));
|
||||
}
|
||||
BX_SB16_MIDIOUT = soundmod->get_midiout();
|
||||
if (BX_SB16_MIDIOUT == NULL) {
|
||||
BX_PANIC(("Couldn't initialize lowlevel driver (midiout)"));
|
||||
if ((BX_SB16_THIS midimode >= 0) && (BX_SB16_THIS midimode <= 3)) {
|
||||
BX_SB16_MIDIOUT = DEV_sound_get_midiout(sb16_midi_drv[BX_SB16_THIS midimode]);
|
||||
if (BX_SB16_MIDIOUT == NULL) {
|
||||
BX_PANIC(("Couldn't initialize midiout driver"));
|
||||
}
|
||||
}
|
||||
|
||||
DSP.dma.chunk = new Bit8u[BX_SOUNDLOW_WAVEPACKETSIZE];
|
||||
@ -438,7 +440,6 @@ void bx_sb16_c::register_state(void)
|
||||
new bx_shadow_bool_c(mpu, "irqpending", &MPU.irqpending);
|
||||
new bx_shadow_bool_c(mpu, "forceuartmode", &MPU.forceuartmode);
|
||||
new bx_shadow_bool_c(mpu, "singlecommand", &MPU.singlecommand);
|
||||
new bx_shadow_bool_c(mpu, "outputinit", &MPU.outputinit);
|
||||
new bx_shadow_num_c(mpu, "current_timer", &MPU.current_timer);
|
||||
new bx_shadow_num_c(mpu, "last_delta_time", &MPU.last_delta_time);
|
||||
bx_list_c *patchtbl = new bx_list_c(mpu, "patchtable");
|
||||
@ -530,9 +531,17 @@ void bx_sb16_c::runtime_config_handler(void *this_ptr)
|
||||
void bx_sb16_c::runtime_config(void)
|
||||
{
|
||||
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_SOUND_SB16);
|
||||
if (BX_SB16_THIS midi_changed) {
|
||||
if (BX_SB16_THIS midi_changed != 0) {
|
||||
BX_SB16_THIS closemidioutput();
|
||||
BX_SB16_THIS midimode = SIM->get_param_num("midimode", base)->get();
|
||||
if (BX_SB16_THIS midi_changed & 1) {
|
||||
BX_SB16_THIS midimode = SIM->get_param_num("midimode", base)->get();
|
||||
if ((BX_SB16_THIS midimode >= 0) && (BX_SB16_THIS midimode <= 3)) {
|
||||
BX_SB16_MIDIOUT = DEV_sound_get_midiout(sb16_midi_drv[BX_SB16_THIS midimode]);
|
||||
if (BX_SB16_MIDIOUT == NULL) {
|
||||
BX_PANIC(("Couldn't initialize midiout driver"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// writemidicommand() re-opens the output device / file on demand
|
||||
BX_SB16_THIS midi_changed = 0;
|
||||
}
|
||||
@ -2378,55 +2387,26 @@ Bit32u fmopl_callback(void *dev, Bit16u rate, Bit8u *buffer, Bit32u len)
|
||||
|
||||
/* Handlers for the midi commands/midi file output */
|
||||
|
||||
// Write the header of the midi file. Track length is 0x7fffffff
|
||||
// until we know how long it's really going to be
|
||||
|
||||
void bx_sb16_c::initmidifile()
|
||||
{
|
||||
struct {
|
||||
Bit8u chunk[4];
|
||||
Bit32u chunklen; // all values in BIG Endian!
|
||||
Bit16u smftype;
|
||||
Bit16u tracknum;
|
||||
Bit16u timecode; // 0x80 + deltatimesperquarter << 8
|
||||
} midiheader =
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
{ "MTh", 0x06000000, 0, 0x0100, 0x8001 };
|
||||
#else
|
||||
{ "MTh", 6, 0, 1, 0x180 };
|
||||
#endif
|
||||
midiheader.chunk[3] = 'd';
|
||||
|
||||
struct {
|
||||
Bit8u chunk[4];
|
||||
Bit32u chunklen;
|
||||
Bit8u data[15];
|
||||
} trackheader =
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
{ "MTr", 0xffffff7f,
|
||||
#else
|
||||
{ "MTr", 0x7fffffff,
|
||||
#endif
|
||||
{ 0x00,0xff,0x51,3,0x07,0xa1,0x20, // set tempo 120 (0x7a120 us per quarter)
|
||||
0x00,0xff,0x58,4,4,2,0x18,0x08 }}; // time sig 4/4
|
||||
trackheader.chunk[3] = 'k';
|
||||
|
||||
fwrite(&midiheader, 1, 14, MIDIDATA);
|
||||
fwrite(&trackheader, 1, 23, MIDIDATA);
|
||||
}
|
||||
|
||||
// write the midi command to the midi file
|
||||
|
||||
void bx_sb16_c::writemidicommand(int command, int length, Bit8u data[])
|
||||
{
|
||||
bx_param_string_c *midiparam;
|
||||
|
||||
/* We need to determine the time elapsed since the last MIDI command */
|
||||
int deltatime = currentdeltatime();
|
||||
|
||||
/* Initialize output device if necessary and not done yet */
|
||||
if (BX_SB16_THIS midimode == 1) {
|
||||
/* Initialize output device/file if necessary and not done yet */
|
||||
if (BX_SB16_THIS midimode > 0) {
|
||||
if (MPU.outputinit != 1) {
|
||||
writelog(MIDILOG(4), "Initializing Midi output.");
|
||||
if (BX_SB16_MIDIOUT->openmidioutput(SIM->get_param_string(BXPN_SOUND_MIDIOUT)->getptr()) == BX_SOUNDLOW_OK)
|
||||
if (BX_SB16_THIS midimode == 1) {
|
||||
midiparam = SIM->get_param_string(BXPN_SOUND_MIDIOUT);
|
||||
} else {
|
||||
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_SOUND_SB16);
|
||||
midiparam = SIM->get_param_string("midi", base);
|
||||
}
|
||||
if (BX_SB16_MIDIOUT->openmidioutput(midiparam->getptr()) == BX_SOUNDLOW_OK)
|
||||
MPU.outputinit = 1;
|
||||
else
|
||||
MPU.outputinit = 0;
|
||||
@ -2437,35 +2417,7 @@ void bx_sb16_c::writemidicommand(int command, int length, Bit8u data[])
|
||||
}
|
||||
}
|
||||
BX_SB16_MIDIOUT->sendmidicommand(deltatime, command, length, data);
|
||||
return;
|
||||
} else if ((BX_SB16_THIS midimode == 2) ||
|
||||
(BX_SB16_THIS midimode == 3)) {
|
||||
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_SOUND_SB16);
|
||||
bx_param_string_c *midiparam = SIM->get_param_string("midi", base);
|
||||
if ((MIDIDATA == NULL) && (!midiparam->isempty())) {
|
||||
MIDIDATA = fopen(midiparam->getptr(),"wb");
|
||||
if (MIDIDATA == NULL) {
|
||||
writelog (MIDILOG(2), "Error opening file %s. Midimode disabled.",
|
||||
midiparam->getptr());
|
||||
BX_SB16_THIS midimode = 0;
|
||||
} else if (BX_SB16_THIS midimode == 2) {
|
||||
initmidifile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BX_SB16_THIS midimode < 2)
|
||||
return;
|
||||
|
||||
if (BX_SB16_THIS midimode == 2)
|
||||
writedeltatime(deltatime);
|
||||
|
||||
fputc(command, MIDIDATA);
|
||||
if ((command == 0xf0) ||
|
||||
(command == 0xf7)) // write event length for sysex/meta events
|
||||
writedeltatime(length);
|
||||
|
||||
fwrite(data, 1, length, MIDIDATA);
|
||||
}
|
||||
|
||||
// determine how many delta times have passed since
|
||||
@ -2594,86 +2546,13 @@ void bx_sb16_c::midiremapprogram(int channel)
|
||||
}
|
||||
}
|
||||
|
||||
// convert a number into a delta time coded value
|
||||
int bx_sb16_c::converttodeltatime(Bit32u deltatime, Bit8u value[4])
|
||||
{
|
||||
int i, count;
|
||||
Bit8u outbytes[4];
|
||||
|
||||
count = 0;
|
||||
|
||||
if (deltatime <= 0)
|
||||
{
|
||||
count = 1;
|
||||
value[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((deltatime > 0) && (count < 4)) // split into parts
|
||||
{ // of seven bits
|
||||
outbytes[count++] = deltatime & 0x7f;
|
||||
deltatime >>= 7;
|
||||
}
|
||||
for (i=0; i<count; i++) // reverse order and
|
||||
value[i] = outbytes[count - i - 1] | 0x80; // set eighth bit on
|
||||
value[count - 1] &= 0x7f; // all but last byte
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// write a delta time coded value to the midi file
|
||||
void bx_sb16_c::writedeltatime(Bit32u deltatime)
|
||||
{
|
||||
Bit8u outbytes[4];
|
||||
|
||||
int count = converttodeltatime(deltatime, outbytes);
|
||||
|
||||
for (int i=0; i<count; i++)
|
||||
fputc(outbytes[i], MIDIDATA);
|
||||
}
|
||||
|
||||
|
||||
// close the midi file, and set the track length accordingly
|
||||
|
||||
void bx_sb16_c::finishmidifile()
|
||||
{
|
||||
struct {
|
||||
Bit8u delta, statusbyte, metaevent, length;
|
||||
} metatrackend = { 0, 0xff, 0x2f, 0 };
|
||||
|
||||
// Meta event track end (0xff 0x2f 0x00) plus leading delta time
|
||||
fwrite(&metatrackend, 1, sizeof(metatrackend), MIDIDATA);
|
||||
|
||||
Bit32u tracklen = ftell(MIDIDATA);
|
||||
if (tracklen < 0)
|
||||
BX_PANIC (("ftell failed in finishmidifile"));
|
||||
if (tracklen < 22)
|
||||
BX_PANIC (("finishmidifile with track length too short"));
|
||||
tracklen -= 22; // subtract the midi file and track header
|
||||
fseek(MIDIDATA, 22 - 4, SEEK_SET);
|
||||
// value has to be in big endian
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
tracklen = bx_bswap32(tracklen);
|
||||
#endif
|
||||
fwrite(&tracklen, 4, 1, MIDIDATA);
|
||||
}
|
||||
|
||||
void bx_sb16_c::closemidioutput()
|
||||
{
|
||||
switch (BX_SB16_THIS midimode) {
|
||||
case 1:
|
||||
if (MPU.outputinit != 0) {
|
||||
MPU.outputinit = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (MIDIDATA != NULL)
|
||||
finishmidifile();
|
||||
case 3:
|
||||
if (MIDIDATA != NULL)
|
||||
fclose(MIDIDATA);
|
||||
MIDIDATA = NULL;
|
||||
break;
|
||||
if (BX_SB16_THIS midimode > 0) {
|
||||
if (MPU.outputinit != 0) {
|
||||
BX_SB16_MIDIOUT->closemidioutput();
|
||||
MPU.outputinit = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3238,7 +3117,7 @@ Bit64s bx_sb16_c::sb16_param_handler(bx_param_c *param, int set, Bit64s val)
|
||||
BX_SB16_THIS loglevel = (int)val;
|
||||
} else if (!strcmp(pname, "midimode")) {
|
||||
if (val != BX_SB16_THIS midimode) {
|
||||
BX_SB16_THIS midi_changed = 1;
|
||||
BX_SB16_THIS midi_changed |= 1;
|
||||
}
|
||||
} else if (!strcmp(pname, "wavemode")) {
|
||||
if (val != BX_SB16_THIS wavemode) {
|
||||
@ -3260,7 +3139,7 @@ const char* bx_sb16_c::sb16_param_string_handler(bx_param_string_c *param, int s
|
||||
if (!strcmp(pname, "wave")) {
|
||||
BX_SB16_THIS wave_changed = 1;
|
||||
} else if (!strcmp(pname, "midi")) {
|
||||
BX_SB16_THIS midi_changed = 1;
|
||||
BX_SB16_THIS midi_changed |= 2;
|
||||
} else if (!strcmp(pname, "log")) {
|
||||
if (LOGFILE != NULL) {
|
||||
fclose(LOGFILE);
|
||||
|
@ -152,10 +152,10 @@ public:
|
||||
private:
|
||||
|
||||
int midimode, wavemode, loglevel;
|
||||
bx_bool midi_changed, wave_changed;
|
||||
bx_bool wave_changed;
|
||||
Bit8u midi_changed;
|
||||
Bit32u dmatimer;
|
||||
FILE *logfile, *midifile, *wavefile; // the output files or devices
|
||||
bx_sound_lowlevel_c *soundmod; // the lowlevel class
|
||||
FILE *logfile, *wavefile; // the output files or devices
|
||||
bx_soundlow_waveout_c *waveout; // waveout support
|
||||
bx_soundlow_wavein_c *wavein; // wavein support
|
||||
bx_soundlow_midiout_c *midiout; // midiout support
|
||||
@ -293,14 +293,10 @@ private:
|
||||
BX_SB16_SMF int currentdeltatime();
|
||||
BX_SB16_SMF void processmidicommand(bx_bool force);
|
||||
BX_SB16_SMF void midiremapprogram(int channel); // remap program change
|
||||
BX_SB16_SMF int converttodeltatime(Bit32u deltatime, Bit8u value[4]);
|
||||
BX_SB16_SMF void writemidicommand(int command, int length, Bit8u data[]);
|
||||
BX_SB16_SMF void writedeltatime(Bit32u deltatime); // write in delta time coding
|
||||
|
||||
BX_SB16_SMF void initmidifile(); // write midi file header
|
||||
BX_SB16_SMF void closemidioutput(); // close midi file / device
|
||||
BX_SB16_SMF void closewaveoutput(); // close wave file
|
||||
BX_SB16_SMF void finishmidifile(); // write track length etc.
|
||||
BX_SB16_SMF void finishvocfile(); // close voc file
|
||||
BX_SB16_SMF void create_logfile();
|
||||
|
||||
|
@ -273,9 +273,7 @@ bx_soundlow_midiout_alsa_c::bx_soundlow_midiout_alsa_c()
|
||||
|
||||
bx_soundlow_midiout_alsa_c::~bx_soundlow_midiout_alsa_c()
|
||||
{
|
||||
if (alsa_seq.handle != NULL) {
|
||||
snd_seq_close(alsa_seq.handle);
|
||||
}
|
||||
closemidioutput();
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_alsa_c::alsa_seq_open(const char *alsadev)
|
||||
@ -415,6 +413,15 @@ int bx_soundlow_midiout_alsa_c::sendmidicommand(int delta, int command, int leng
|
||||
return BX_SOUNDLOW_ERR;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_alsa_c::closemidioutput()
|
||||
{
|
||||
if (alsa_seq.handle != NULL) {
|
||||
snd_seq_close(alsa_seq.handle);
|
||||
alsa_seq.handle = NULL;
|
||||
}
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
// bx_sound_alsa_c class implemenzation
|
||||
|
||||
bx_sound_alsa_c::bx_sound_alsa_c()
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
private:
|
||||
int alsa_seq_open(const char *alsadev);
|
||||
|
@ -167,30 +167,7 @@ bx_soundlow_midiout_file_c::bx_soundlow_midiout_file_c()
|
||||
|
||||
bx_soundlow_midiout_file_c::~bx_soundlow_midiout_file_c()
|
||||
{
|
||||
struct {
|
||||
Bit8u delta, statusbyte, metaevent, length;
|
||||
} metatrackend = { 0, 0xff, 0x2f, 0 };
|
||||
|
||||
if (midifile != NULL) {
|
||||
if (type == BX_SOUNDFILE_MID) {
|
||||
// Meta event track end (0xff 0x2f 0x00) plus leading delta time
|
||||
fwrite(&metatrackend, 1, sizeof(metatrackend), midifile);
|
||||
|
||||
Bit32u tracklen = ftell(midifile);
|
||||
if (tracklen < 0)
|
||||
BX_PANIC (("ftell failed in finishmidifile"));
|
||||
if (tracklen < 22)
|
||||
BX_PANIC (("MIDI track length too short"));
|
||||
tracklen -= 22; // subtract the midi file and track header
|
||||
fseek(midifile, 22 - 4, SEEK_SET);
|
||||
// value has to be in big endian
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
tracklen = bx_bswap32(tracklen);
|
||||
#endif
|
||||
fwrite(&tracklen, 4, 1, midifile);
|
||||
}
|
||||
fclose(midifile);
|
||||
}
|
||||
closemidioutput();
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_file_c::openmidioutput(const char *mididev)
|
||||
@ -263,6 +240,36 @@ int bx_soundlow_midiout_file_c::sendmidicommand(int delta, int command, int leng
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_file_c::closemidioutput()
|
||||
{
|
||||
struct {
|
||||
Bit8u delta, statusbyte, metaevent, length;
|
||||
} metatrackend = { 0, 0xff, 0x2f, 0 };
|
||||
|
||||
if (midifile != NULL) {
|
||||
if (type == BX_SOUNDFILE_MID) {
|
||||
// Meta event track end (0xff 0x2f 0x00) plus leading delta time
|
||||
fwrite(&metatrackend, 1, sizeof(metatrackend), midifile);
|
||||
|
||||
Bit32u tracklen = ftell(midifile);
|
||||
if (tracklen < 0)
|
||||
BX_PANIC (("ftell failed in finishmidifile"));
|
||||
if (tracklen < 22)
|
||||
BX_PANIC (("MIDI track length too short"));
|
||||
tracklen -= 22; // subtract the midi file and track header
|
||||
fseek(midifile, 22 - 4, SEEK_SET);
|
||||
// value has to be in big endian
|
||||
#ifdef BX_LITTLE_ENDIAN
|
||||
tracklen = bx_bswap32(tracklen);
|
||||
#endif
|
||||
fwrite(&tracklen, 4, 1, midifile);
|
||||
}
|
||||
fclose(midifile);
|
||||
midifile = NULL;
|
||||
}
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
void bx_soundlow_midiout_file_c::writedeltatime(Bit32u deltatime)
|
||||
{
|
||||
int i, count = 0;
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
virtual int openwaveoutput(const char *wavedev);
|
||||
virtual int set_pcm_params(bx_pcm_param_t *param);
|
||||
virtual int output(int length, Bit8u data[]);
|
||||
|
||||
private:
|
||||
void initvocfile();
|
||||
void initwavfile();
|
||||
@ -47,6 +48,7 @@ public:
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
private:
|
||||
void writedeltatime(Bit32u deltatime);
|
||||
|
@ -303,7 +303,7 @@ bx_soundlow_midiout_oss_c::bx_soundlow_midiout_oss_c()
|
||||
|
||||
bx_soundlow_midiout_oss_c::~bx_soundlow_midiout_oss_c()
|
||||
{
|
||||
fclose(midi);
|
||||
closemidioutput();
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_oss_c::openmidioutput(const char *mididev)
|
||||
@ -323,11 +323,6 @@ int bx_soundlow_midiout_oss_c::openmidioutput(const char *mididev)
|
||||
}
|
||||
|
||||
|
||||
int bx_soundlow_midiout_oss_c::midiready()
|
||||
{
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_oss_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
|
||||
{
|
||||
UNUSED(delta);
|
||||
@ -339,6 +334,15 @@ int bx_soundlow_midiout_oss_c::sendmidicommand(int delta, int command, int lengt
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_oss_c::closemidioutput()
|
||||
{
|
||||
if (midi != NULL) {
|
||||
fclose(midi);
|
||||
midi = NULL;
|
||||
}
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
// bx_sound_oss_c class implemenzation
|
||||
|
||||
bx_sound_oss_c::bx_sound_oss_c()
|
||||
|
@ -60,8 +60,8 @@ public:
|
||||
virtual ~bx_soundlow_midiout_oss_c();
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int midiready();
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
private:
|
||||
FILE *midi;
|
||||
|
@ -426,6 +426,11 @@ int bx_soundlow_midiout_c::sendmidicommand(int delta, int command, int length, B
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_c::closemidioutput()
|
||||
{
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
// bx_sound_lowlevel_c class implemenzation
|
||||
// This is the base class of the sound lowlevel support.
|
||||
|
||||
|
@ -122,6 +122,7 @@ public:
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int midiready();
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
};
|
||||
|
||||
// the lowlevel sound driver class returns pointers to the child objects
|
||||
|
@ -65,72 +65,140 @@ void CDECL libsoundmod_LTX_plugin_fini(void)
|
||||
bx_soundmod_ctl_c::bx_soundmod_ctl_c()
|
||||
{
|
||||
put("soundctl", "SNDCTL");
|
||||
soundmod = NULL;
|
||||
n_sound_drivers = 0;
|
||||
waveout = NULL;
|
||||
}
|
||||
|
||||
bx_soundmod_ctl_c::~bx_soundmod_ctl_c()
|
||||
{
|
||||
delete soundmod;
|
||||
for (unsigned i = 0; i < n_sound_drivers; i++) {
|
||||
delete soundmod[i].module;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_soundmod_ctl_c::init()
|
||||
{
|
||||
int ret;
|
||||
static const char default_name[] = BX_SOUND_LOWLEVEL_NAME;
|
||||
const char *driver = SIM->get_param_string(BXPN_SOUND_DRIVER)->getptr();
|
||||
const char *pwaveout = SIM->get_param_string(BXPN_SOUND_WAVEOUT)->getptr();
|
||||
const char *wavein = SIM->get_param_string(BXPN_SOUND_WAVEIN)->getptr();
|
||||
|
||||
if (strcmp(driver, "default") == 0) {
|
||||
driver = default_name;
|
||||
}
|
||||
|
||||
if (strcmp(driver, "dummy") == 0) {
|
||||
soundmod = new bx_sound_lowlevel_c();
|
||||
} else if (!strcmp(driver, "file")) {
|
||||
soundmod = new bx_sound_file_c();
|
||||
#if BX_HAVE_ALSASOUND
|
||||
} else if (!strcmp(driver, "alsa")) {
|
||||
soundmod = new bx_sound_alsa_c();
|
||||
#endif
|
||||
#if BX_WITH_SDL || BX_WITH_SDL2
|
||||
} else if (!strcmp(driver, "sdl")) {
|
||||
soundmod = new bx_sound_sdl_c();
|
||||
#endif
|
||||
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
|
||||
} else if (!strcmp(driver, "oss")) {
|
||||
soundmod = new bx_sound_oss_c();
|
||||
#endif
|
||||
#if defined(macintosh)
|
||||
} else if (!strcmp(driver, "osx")) {
|
||||
soundmod = new bx_sound_osx_c();
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
} else if (!strcmp(driver, "win")) {
|
||||
soundmod = new bx_sound_windows_c();
|
||||
#endif
|
||||
} else {
|
||||
BX_PANIC(("unknown lowlevel sound driver '%s'", driver));
|
||||
return;
|
||||
}
|
||||
if (!strlen(wavein)) {
|
||||
SIM->get_param_string(BXPN_SOUND_WAVEIN)->set(pwaveout);
|
||||
}
|
||||
waveout = soundmod->get_waveout();
|
||||
if (waveout != NULL) {
|
||||
ret = waveout->openwaveoutput(pwaveout);
|
||||
if (ret != BX_SOUNDLOW_OK) {
|
||||
BX_PANIC(("Could not open wave output device"));
|
||||
if (get_driver(driver) != NULL) {
|
||||
if (!strlen(wavein)) {
|
||||
SIM->get_param_string(BXPN_SOUND_WAVEIN)->set(pwaveout);
|
||||
}
|
||||
waveout = soundmod[0].module->get_waveout();
|
||||
if (waveout != NULL) {
|
||||
ret = waveout->openwaveoutput(pwaveout);
|
||||
if (ret != BX_SOUNDLOW_OK) {
|
||||
BX_PANIC(("Could not open wave output device"));
|
||||
}
|
||||
} else {
|
||||
BX_PANIC(("no waveout support in sound driver '%s'", driver));
|
||||
}
|
||||
} else {
|
||||
BX_PANIC(("no waveout support in sound driver '%s'", driver));
|
||||
}
|
||||
}
|
||||
|
||||
void* bx_soundmod_ctl_c::get_module()
|
||||
bx_sound_lowlevel_c* bx_soundmod_ctl_c::get_driver(const char *name)
|
||||
{
|
||||
return soundmod;
|
||||
static const char default_name[] = BX_SOUND_LOWLEVEL_NAME;
|
||||
bx_sound_lowlevel_c *driver = NULL;
|
||||
unsigned i;
|
||||
|
||||
if (strcmp(name, "default") == 0) {
|
||||
name = default_name;
|
||||
}
|
||||
for (i = 0; i < n_sound_drivers; i++) {
|
||||
if (!strcmp(name, soundmod[i].name)) {
|
||||
return soundmod[i].module;
|
||||
}
|
||||
}
|
||||
if (i == BX_MAX_SOUND_DRIVERS) {
|
||||
BX_PANIC(("Too many sound drivers!"));
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(name, "dummy") == 0) {
|
||||
driver = new bx_sound_lowlevel_c();
|
||||
} else if (!strcmp(name, "file")) {
|
||||
driver = new bx_sound_file_c();
|
||||
#if BX_HAVE_ALSASOUND
|
||||
} else if (!strcmp(name, "alsa")) {
|
||||
driver = new bx_sound_alsa_c();
|
||||
#endif
|
||||
#if BX_WITH_SDL || BX_WITH_SDL2
|
||||
} else if (!strcmp(name, "sdl")) {
|
||||
driver = new bx_sound_sdl_c();
|
||||
#endif
|
||||
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
|
||||
} else if (!strcmp(name, "oss")) {
|
||||
driver = new bx_sound_oss_c();
|
||||
#endif
|
||||
#if defined(macintosh)
|
||||
} else if (!strcmp(name, "osx")) {
|
||||
driver = new bx_sound_osx_c();
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
} else if (!strcmp(name, "win")) {
|
||||
driver = new bx_sound_windows_c();
|
||||
#endif
|
||||
} else {
|
||||
BX_PANIC(("unknown lowlevel sound driver '%s'", name));
|
||||
}
|
||||
if (driver != NULL) {
|
||||
BX_INFO(("Installed sound driver '%s' at index #%d", name, i));
|
||||
strcpy(soundmod[i].name, name);
|
||||
soundmod[i].module = driver;
|
||||
n_sound_drivers++;
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
|
||||
bx_soundlow_waveout_c* bx_soundmod_ctl_c::get_waveout(const char *driver)
|
||||
{
|
||||
bx_sound_lowlevel_c *module = NULL;
|
||||
|
||||
if (!strcmp(driver, "default")) {
|
||||
module = soundmod[0].module;
|
||||
} else {
|
||||
module = get_driver(driver);
|
||||
}
|
||||
if (module != NULL) {
|
||||
return module->get_waveout();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bx_soundlow_wavein_c* bx_soundmod_ctl_c::get_wavein(const char *driver)
|
||||
{
|
||||
bx_sound_lowlevel_c *module = NULL;
|
||||
|
||||
if (!strcmp(driver, "default")) {
|
||||
module = soundmod[0].module;
|
||||
} else {
|
||||
module = get_driver(driver);
|
||||
}
|
||||
if (module != NULL) {
|
||||
return module->get_wavein();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bx_soundlow_midiout_c* bx_soundmod_ctl_c::get_midiout(const char *driver)
|
||||
{
|
||||
bx_sound_lowlevel_c *module = NULL;
|
||||
|
||||
if (!strcmp(driver, "default")) {
|
||||
module = soundmod[0].module;
|
||||
} else {
|
||||
module = get_driver(driver);
|
||||
}
|
||||
if (module != NULL) {
|
||||
return module->get_midiout();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handlers for the VOC file output */
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
// Common code for sound lowlevel modules
|
||||
|
||||
#define BX_MAX_SOUND_DRIVERS 4
|
||||
|
||||
class bx_sound_lowlevel_c;
|
||||
class bx_soundlow_waveout_c;
|
||||
|
||||
@ -29,11 +31,20 @@ public:
|
||||
bx_soundmod_ctl_c();
|
||||
virtual ~bx_soundmod_ctl_c();
|
||||
virtual void init(void);
|
||||
virtual void* get_module();
|
||||
virtual bx_soundlow_waveout_c* get_waveout(const char *driver);
|
||||
virtual bx_soundlow_wavein_c* get_wavein(const char *driver);
|
||||
virtual bx_soundlow_midiout_c* get_midiout(const char *driver);
|
||||
virtual void VOC_init_file(FILE *stream);
|
||||
virtual void VOC_write_block(FILE *stream, int block, Bit32u headerlen,
|
||||
Bit8u header[], Bit32u datalen, Bit8u data[]);
|
||||
private:
|
||||
bx_sound_lowlevel_c *soundmod;
|
||||
bx_sound_lowlevel_c* get_driver(const char *name);
|
||||
|
||||
struct {
|
||||
char name[8];
|
||||
bx_sound_lowlevel_c *module;
|
||||
} soundmod[BX_MAX_SOUND_DRIVERS];
|
||||
unsigned n_sound_drivers;
|
||||
|
||||
bx_soundlow_waveout_c *waveout;
|
||||
};
|
||||
|
@ -461,11 +461,7 @@ bx_soundlow_midiout_osx_c::bx_soundlow_midiout_osx_c()
|
||||
|
||||
bx_soundlow_midiout_osx_c::~bx_soundlow_midiout_osx_c()
|
||||
{
|
||||
MidiOpen = 0;
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
AUGraphStop(MidiGraph);
|
||||
AUGraphClose(MidiGraph);
|
||||
#endif
|
||||
closemidioutput();
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_osx_c::openmidioutput(const char *mididev)
|
||||
@ -533,6 +529,16 @@ int bx_soundlow_midiout_osx_c::sendmidicommand(int delta, int command, int lengt
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_osx_c::closemidioutput()
|
||||
{
|
||||
MidiOpen = 0;
|
||||
#ifdef BX_SOUND_OSX_use_converter
|
||||
AUGraphStop(MidiGraph);
|
||||
AUGraphClose(MidiGraph);
|
||||
#endif
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
// bx_sound_osx_c class implemenzation
|
||||
|
||||
bx_sound_osx_c::bx_sound_osx_c()
|
||||
|
@ -69,6 +69,7 @@ public:
|
||||
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
private:
|
||||
int MidiOpen;
|
||||
|
@ -353,15 +353,7 @@ bx_soundlow_midiout_win_c::bx_soundlow_midiout_win_c()
|
||||
|
||||
bx_soundlow_midiout_win_c::~bx_soundlow_midiout_win_c()
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if (MidiOpen == 1) {
|
||||
ret = midiOutReset(MidiOut);
|
||||
if (ismidiready == 0)
|
||||
checkmidiready(); // to clear any pending SYSEX
|
||||
ret = midiOutClose(MidiOut);
|
||||
BX_DEBUG(("midiOutClose() = %d", ret));
|
||||
}
|
||||
closemidioutput();
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_win_c::openmidioutput(const char *mididev)
|
||||
@ -438,6 +430,20 @@ int bx_soundlow_midiout_win_c::sendmidicommand(int delta, int command, int lengt
|
||||
return (ret == 0) ? BX_SOUNDLOW_OK : BX_SOUNDLOW_ERR;
|
||||
}
|
||||
|
||||
int bx_soundlow_midiout_win_c::closemidioutput()
|
||||
{
|
||||
UINT ret;
|
||||
|
||||
if (MidiOpen == 1) {
|
||||
ret = midiOutReset(MidiOut);
|
||||
if (ismidiready == 0)
|
||||
checkmidiready(); // to clear any pending SYSEX
|
||||
ret = midiOutClose(MidiOut);
|
||||
BX_DEBUG(("midiOutClose() = %d", ret));
|
||||
}
|
||||
return BX_SOUNDLOW_OK;
|
||||
}
|
||||
|
||||
void bx_soundlow_midiout_win_c::checkmidiready()
|
||||
{
|
||||
if ((MidiHeader->dwFlags & MHDR_DONE) != 0) {
|
||||
|
@ -207,6 +207,7 @@ public:
|
||||
virtual int openmidioutput(const char *mididev);
|
||||
virtual int midiready();
|
||||
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
||||
virtual int closemidioutput();
|
||||
|
||||
private:
|
||||
HMIDIOUT MidiOut; // Midi output device
|
||||
|
@ -178,11 +178,7 @@ void bx_speaker_c::init(void)
|
||||
if (!strcmp(mode, "sound")) {
|
||||
output_mode = BX_SPK_MODE_SOUND;
|
||||
#if BX_SUPPORT_SOUNDLOW
|
||||
bx_sound_lowlevel_c *soundmod = DEV_sound_get_module();
|
||||
if (soundmod == NULL) {
|
||||
BX_PANIC(("Couldn't initialize lowlevel driver"));
|
||||
}
|
||||
waveout = soundmod->get_waveout();
|
||||
waveout = DEV_sound_get_waveout("default");
|
||||
if (waveout != NULL) {
|
||||
beep_active = 0;
|
||||
BX_INIT_MUTEX(beep_mutex);
|
||||
@ -190,6 +186,7 @@ void bx_speaker_c::init(void)
|
||||
BX_INFO(("Using lowlevel sound support for output"));
|
||||
} else {
|
||||
BX_ERROR(("Failed to use lowlevel sound support for output"));
|
||||
output_mode = BX_SPK_MODE_NONE;
|
||||
}
|
||||
#endif
|
||||
} else if (!strcmp(mode, "system")) {
|
||||
|
@ -255,8 +255,9 @@ extern "C" {
|
||||
#define DEV_usb_send_msg(a,b) bx_devices.pluginUsbDevCtl->usb_send_msg((void*)a,b)
|
||||
|
||||
///////// Sound module macros
|
||||
#define DEV_sound_get_module() \
|
||||
((bx_sound_lowlevel_c*)bx_devices.pluginSoundModCtl->get_module())
|
||||
#define DEV_sound_get_waveout(a) (bx_devices.pluginSoundModCtl->get_waveout(a))
|
||||
#define DEV_sound_get_wavein(a) (bx_devices.pluginSoundModCtl->get_wavein(a))
|
||||
#define DEV_sound_get_midiout(a) (bx_devices.pluginSoundModCtl->get_midiout(a))
|
||||
#define DEV_soundmod_VOC_init_file(a) \
|
||||
(bx_devices.pluginSoundModCtl->VOC_init_file(a))
|
||||
#define DEV_soundmod_VOC_write_block(a,b,c,d,e,f) \
|
||||
|
Loading…
Reference in New Issue
Block a user