1 /////////////////////////////////////////////////////////////////////////
2 // $Id: sb16.cc,v 1.61 2008/07/20 21:05:21 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2002 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /////////////////////////////////////////////////////////////////////////
29 // This file (SB16.CC) written and donated by Josef Drexler
31 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
32 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
33 // is used to know when we are exporting symbols and when we are importing.
43 #define LOG_THIS theSB16Device->
45 bx_sb16_c
*theSB16Device
= NULL
;
47 int libsb16_LTX_plugin_init(plugin_t
*plugin
, plugintype_t type
, int argc
, char *argv
[])
49 theSB16Device
= new bx_sb16_c();
50 bx_devices
.pluginSB16Device
= theSB16Device
;
51 BX_REGISTER_DEVICE_DEVMODEL(plugin
, type
, theSB16Device
, BX_PLUGIN_SB16
);
55 void libsb16_LTX_plugin_fini(void)
60 // some shortcuts to save typing
61 #define LOGFILE BX_SB16_THIS logfile
62 #define MIDIDATA BX_SB16_THIS midifile
63 #define WAVEDATA BX_SB16_THIS wavefile
64 #define MPU BX_SB16_THIS mpu401
65 #define DSP BX_SB16_THIS dsp
66 #define MIXER BX_SB16_THIS mixer
67 #define EMUL BX_SB16_THIS emuldata
68 #define OPL BX_SB16_THIS opl
70 #define BX_SB16_OUTPUT BX_SB16_THIS output
72 // here's a safe way to print out null pointeres
73 #define MIGHT_BE_NULL(x) ((x==NULL)? "(null)" : x)
75 bx_sb16_c::bx_sb16_c(void)
79 mpu401
.timer_handle
= BX_NULL_TIMER_HANDLE
;
80 dsp
.timer_handle
= BX_NULL_TIMER_HANDLE
;
81 opl
.timer_handle
= BX_NULL_TIMER_HANDLE
;
89 bx_sb16_c::~bx_sb16_c(void)
98 if (MPU
.outputinit
!= 0)
99 BX_SB16_OUTPUT
->closemidioutput();
102 if (MIDIDATA
!= NULL
)
110 if (WAVEDATA
!= NULL
)
114 if (DSP
.outputinit
!= 0)
115 BX_SB16_OUTPUT
->closewaveoutput();
118 if (WAVEDATA
!= NULL
)
123 delete(BX_SB16_OUTPUT
);
125 delete [] DSP
.dma
.chunk
;
127 if ((SIM
->get_param_num(BXPN_SB16_LOGLEVEL
)->get() > 0) && LOGFILE
)
130 SIM
->get_param_num(BXPN_SB16_DMATIMER
)->set_handler(NULL
);
131 SIM
->get_param_num(BXPN_SB16_LOGLEVEL
)->set_handler(NULL
);
136 void bx_sb16_c::init(void)
141 base
= (bx_list_c
*) SIM
->get_param(BXPN_SB16
);
142 if ((strlen(SIM
->get_param_string("logfile", base
)->getptr()) < 1))
143 SIM
->get_param_num("loglevel", base
)->set(0);
145 if (SIM
->get_param_num("loglevel", base
)->get() > 0)
147 LOGFILE
= fopen(SIM
->get_param_string("logfile", base
)->getptr(),"w"); // logfile for errors etc.
150 BX_ERROR(("Error opening file %s. Logging disabled.", SIM
->get_param_string("logfile", base
)->getptr()));
151 SIM
->get_param_num("loglevel", base
)->set(0);
154 BX_SB16_THIS midimode
= SIM
->get_param_num("midimode", base
)->get();
155 BX_SB16_THIS wavemode
= SIM
->get_param_num("wavemode", base
)->get();
156 BX_SB16_THIS dmatimer
= SIM
->get_param_num("dmatimer", base
)->get();
157 BX_SB16_THIS loglevel
= SIM
->get_param_num("loglevel", base
)->get();
159 // let the output functions initialize
160 BX_SB16_OUTPUT
= new BX_SOUND_OUTPUT_C(BX_SB16_THISP
);
162 if (BX_SB16_OUTPUT
== NULL
)
164 writelog(MIDILOG(2), "Couldn't initialize output devices. Output disabled.");
165 BX_SB16_THIS midimode
= 0;
166 BX_SB16_THIS wavemode
= 0;
169 DSP
.dma
.chunk
= new Bit8u
[BX_SOUND_OUTPUT_WAVEPACKETSIZE
];
170 DSP
.dma
.chunkindex
= 0;
174 if (DSP
.dma
.chunk
== NULL
)
176 writelog(WAVELOG(2), "Couldn't allocate wave buffer - wave output disabled.");
177 BX_SB16_THIS wavemode
= 0;
180 BX_INFO(("midi=%d,%s wave=%d,%s log=%d,%s dmatimer=%d",
181 BX_SB16_THIS midimode
, MIGHT_BE_NULL(SIM
->get_param_string("midifile", base
)->getptr()),
182 BX_SB16_THIS wavemode
, MIGHT_BE_NULL(SIM
->get_param_string("wavefile", base
)->getptr()),
183 BX_SB16_THIS loglevel
, MIGHT_BE_NULL(SIM
->get_param_string("logfile", base
)->getptr()),
184 BX_SB16_THIS dmatimer
));
186 // allocate the FIFO buffers - except for the MPUMIDICMD buffer
187 // these sizes are generous, 16 or 8 would probably be sufficient
188 MPU
.datain
.init((int) 64); // the input
189 MPU
.dataout
.init((int) 64); // and output
190 MPU
.cmd
.init((int) 64); // and command buffers
191 MPU
.midicmd
.init((int) 256); // and the midi command buffer (note- large SYSEX'es have to fit!)
192 DSP
.datain
.init((int) 64); // the DSP input
193 DSP
.dataout
.init((int) 64); // and output buffers
194 EMUL
.datain
.init((int) 64); // the emulator ports
195 EMUL
.dataout
.init((int) 64); // for changing emulator settings
197 // reset all parts of the hardware by
198 // triggering their reset functions
200 // reset the Emulator port
205 MPU
.last_delta_time
= 0xffffffff;
208 DSP
.dma
.highspeed
= 0;
211 DSP
.midiuartmode
= 0;
212 DSP
.resetport
= 1; // so that one call to dsp_reset is sufficient
213 dsp_reset(0); // (reset is 1 to 0 transition)
216 BX_SB16_IRQ
= -1; // will be initialized later by the mixer reset
218 for (i
=0; i
<BX_SB16_MIX_REG
; i
++)
220 MIXER
.reg
[0x00] = 0; // reset register
221 MIXER
.reg
[0x80] = 2; // IRQ 5
222 MIXER
.reg
[0x81] = 2; // 8-bit DMA 1, no 16-bit DMA
223 MIXER
.reg
[0x82] = 2 << 5; // no IRQ pending
224 MIXER
.reg
[0xfd] = 16; // ???
225 MIXER
.reg
[0xfe] = 6; // ???
226 set_irq_dma(); // set the IRQ and DMA
228 // call the mixer reset
229 mixer_writeregister(0x00);
230 mixer_writedata(0x00);
232 // reset the FM emulation
234 OPL
.timer_running
= 0;
235 opl_entermode(single
);
238 memset(&BX_SB16_THIS csp_reg
[0], 0, sizeof(BX_SB16_THIS csp_reg
));
239 BX_SB16_THIS csp_reg
[5] = 0x01;
240 BX_SB16_THIS csp_reg
[9] = 0xf8;
242 // Allocate the IO addresses, 2x0..2xf, 3x0..3x4 and 388..38b
243 for (addr
=BX_SB16_IO
; addr
<BX_SB16_IO
+BX_SB16_IOLEN
; addr
++) {
244 DEV_register_ioread_handler(this, &read_handler
, addr
, "SB16", 1);
245 DEV_register_iowrite_handler(this, &write_handler
, addr
, "SB16", 1);
247 for (addr
=BX_SB16_IOMPU
; addr
<BX_SB16_IOMPU
+BX_SB16_IOMPULEN
; addr
++) {
248 DEV_register_ioread_handler(this, &read_handler
, addr
, "SB16", 1);
249 DEV_register_iowrite_handler(this, &write_handler
, addr
, "SB16", 1);
251 for (addr
=BX_SB16_IOADLIB
; addr
<BX_SB16_IOADLIB
+BX_SB16_IOADLIBLEN
; addr
++) {
252 DEV_register_ioread_handler(this, read_handler
, addr
, "SB16", 1);
253 DEV_register_iowrite_handler(this, write_handler
, addr
, "SB16", 1);
257 "SB16 emulation initialised, IRQ %d, IO %03x/%03x/%03x, DMA %d/%d",
258 BX_SB16_IRQ
, BX_SB16_IO
, BX_SB16_IOMPU
, BX_SB16_IOADLIB
,
259 BX_SB16_DMAL
, BX_SB16_DMAH
);
261 // initialize the timers
262 if (MPU
.timer_handle
== BX_NULL_TIMER_HANDLE
) {
263 MPU
.timer_handle
= bx_pc_system
.register_timer
264 (BX_SB16_THISP
, mpu_timer
, 500000 / 384, 1, 1, "sb16.mpu");
265 // midi timer: active, continuous, 500000 / 384 seconds (384 = delta time, 500000 = sec per beat at 120 bpm. Don't change this!)
268 if (DSP
.timer_handle
== BX_NULL_TIMER_HANDLE
) {
269 DSP
.timer_handle
= bx_pc_system
.register_timer
270 (BX_SB16_THISP
, dsp_dmatimer
, 1, 1, 0, "sb16.dsp");
271 // dma timer: inactive, continuous, frequency variable
274 if (OPL
.timer_handle
== BX_NULL_TIMER_HANDLE
) {
275 OPL
.timer_handle
= bx_pc_system
.register_timer
276 (BX_SB16_THISP
, opl_timer
, 80, 1, 0, "sb16.opl");
277 // opl timer: inactive, continuous, frequency 80us
280 writelog(MIDILOG(4), "Timers initialized, midi %d, dma %d, opl %d",
281 MPU
.timer_handle
, DSP
.timer_handle
, OPL
.timer_handle
);
282 MPU
.current_timer
= 0;
284 // init runtime parameters
285 SIM
->get_param_num(BXPN_SB16_DMATIMER
)->set_handler(sb16_param_handler
);
286 SIM
->get_param_num(BXPN_SB16_DMATIMER
)->set_runtime_param(1);
287 SIM
->get_param_num(BXPN_SB16_LOGLEVEL
)->set_handler(sb16_param_handler
);
288 SIM
->get_param_num(BXPN_SB16_LOGLEVEL
)->set_runtime_param(1);
291 void bx_sb16_c::reset(unsigned type
)
295 void bx_sb16_c::register_state(void)
299 bx_list_c
*chip
, *ins_map
, *item
, *patch
;
301 bx_list_c
*list
= new bx_list_c(SIM
->get_bochs_root(), "sb16", "SB16 State", 8);
302 bx_list_c
*mpu
= new bx_list_c(list
, "mpu", 8);
303 new bx_shadow_bool_c(mpu
, "uartmode", &MPU
.uartmode
);
304 new bx_shadow_bool_c(mpu
, "irqpending", &MPU
.irqpending
);
305 new bx_shadow_bool_c(mpu
, "forceuartmode", &MPU
.forceuartmode
);
306 new bx_shadow_bool_c(mpu
, "singlecommand", &MPU
.singlecommand
);
307 new bx_shadow_bool_c(mpu
, "outputinit", &MPU
.outputinit
);
308 new bx_shadow_num_c(mpu
, "current_timer", &MPU
.current_timer
);
309 new bx_shadow_num_c(mpu
, "last_delta_time", &MPU
.last_delta_time
);
310 bx_list_c
*patchtbl
= new bx_list_c(mpu
, "patchtable", BX_SB16_PATCHTABLESIZE
);
311 for (i
=0; i
<BX_SB16_PATCHTABLESIZE
; i
++) {
312 sprintf(name
, "0x%02x", i
);
313 patch
= new bx_list_c(patchtbl
, name
, 3);
314 new bx_shadow_num_c(patch
, "banklsb", &MPU
.banklsb
[i
]);
315 new bx_shadow_num_c(patch
, "bankmsb", &MPU
.bankmsb
[i
]);
316 new bx_shadow_num_c(patch
, "program", &MPU
.program
[i
]);
318 bx_list_c
*dsp
= new bx_list_c(list
, "dsp", 8);
319 new bx_shadow_num_c(dsp
, "resetport", &DSP
.resetport
, BASE_HEX
);
320 new bx_shadow_num_c(dsp
, "speaker", &DSP
.speaker
, BASE_HEX
);
321 new bx_shadow_num_c(dsp
, "prostereo", &DSP
.prostereo
, BASE_HEX
);
322 new bx_shadow_bool_c(dsp
, "irqpending", &DSP
.irqpending
);
323 new bx_shadow_bool_c(dsp
, "midiuartmode", &DSP
.midiuartmode
);
324 new bx_shadow_num_c(dsp
, "testreg", &DSP
.testreg
, BASE_HEX
);
325 bx_list_c
*dma
= new bx_list_c(dsp
, "dma", 16);
326 new bx_shadow_num_c(dma
, "mode", &DSP
.dma
.mode
);
327 new bx_shadow_num_c(dma
, "bits", &DSP
.dma
.bits
);
328 new bx_shadow_num_c(dma
, "bps", &DSP
.dma
.bps
);
329 new bx_shadow_num_c(dma
, "format", &DSP
.dma
.format
);
330 new bx_shadow_num_c(dma
, "timer", &DSP
.dma
.timer
);
331 new bx_shadow_bool_c(dma
, "fifo", &DSP
.dma
.fifo
);
332 new bx_shadow_bool_c(dma
, "output", &DSP
.dma
.output
);
333 new bx_shadow_bool_c(dma
, "stereo", &DSP
.dma
.stereo
);
334 new bx_shadow_bool_c(dma
, "issigned", &DSP
.dma
.issigned
);
335 new bx_shadow_bool_c(dma
, "highspeed", &DSP
.dma
.highspeed
);
336 new bx_shadow_num_c(dma
, "count", &DSP
.dma
.count
);
337 new bx_shadow_num_c(dma
, "chunkindex", &DSP
.dma
.chunkindex
);
338 new bx_shadow_num_c(dma
, "chunkcount", &DSP
.dma
.chunkcount
);
339 new bx_shadow_num_c(dma
, "timeconstant", &DSP
.dma
.timeconstant
);
340 new bx_shadow_num_c(dma
, "blocklength", &DSP
.dma
.blocklength
);
341 new bx_shadow_num_c(dma
, "samplerate", &DSP
.dma
.samplerate
);
342 new bx_shadow_bool_c(dsp
, "outputinit", &DSP
.outputinit
);
343 new bx_shadow_data_c(list
, "chunk", DSP
.dma
.chunk
, BX_SOUND_OUTPUT_WAVEPACKETSIZE
);
344 bx_list_c
*csp
= new bx_list_c(list
, "csp_reg", 256);
345 for (i
=0; i
<256; i
++) {
346 sprintf(name
, "0x%02x", i
);
347 new bx_shadow_num_c(csp
, name
, &BX_SB16_THIS csp_reg
[i
], BASE_HEX
);
349 bx_list_c
*opl
= new bx_list_c(list
, "opl", 8);
350 new bx_shadow_num_c(opl
, "mode", (Bit8u
*)&OPL
.mode
);
351 new bx_shadow_num_c(opl
, "timer_running", &OPL
.timer_running
);
352 new bx_shadow_num_c(opl
, "midichannels", &OPL
.midichannels
);
353 new bx_shadow_num_c(opl
, "drumchannel", &OPL
.drumchannel
);
354 for (i
=0; i
<2; i
++) {
355 sprintf(name
, "chip%d", i
+1);
356 chip
= new bx_list_c(opl
, name
, 11);
357 new bx_shadow_num_c(chip
, "index", &OPL
.index
[i
]);
358 new bx_shadow_num_c(chip
, "wsenable", &OPL
.wsenable
[i
]);
359 new bx_shadow_num_c(chip
, "timer1", &OPL
.timer
[i
*2]);
360 new bx_shadow_num_c(chip
, "timer2", &OPL
.timer
[i
*2+1]);
361 new bx_shadow_num_c(chip
, "timerinit1", &OPL
.timerinit
[i
*2]);
362 new bx_shadow_num_c(chip
, "timerinit2", &OPL
.timerinit
[i
*2+1]);
363 new bx_shadow_num_c(chip
, "tmask", &OPL
.tmask
[i
]);
364 new bx_shadow_num_c(chip
, "tflag", &OPL
.tflag
[i
]);
365 new bx_shadow_num_c(chip
, "percmode", &OPL
.percmode
[i
]);
366 new bx_shadow_num_c(chip
, "cyhhnote", &OPL
.cyhhnote
[i
]);
367 new bx_shadow_num_c(chip
, "cyhhon", &OPL
.cyhhon
[i
]);
369 bx_list_c
*oper
= new bx_list_c(opl
, "oper", BX_SB16_FM_NOP
);
370 for (i
=0; i
<BX_SB16_FM_NOP
; i
++) {
371 sprintf(name
, "%d", i
);
372 item
= new bx_list_c(oper
, name
, BX_SB16_FM_OPB
);
373 for (j
=0; j
<BX_SB16_FM_OPB
; j
++) {
374 sprintf(name
, "%d", j
);
375 new bx_shadow_num_c(item
, name
, &OPL
.oper
[i
][j
]);
378 bx_list_c
*chan
= new bx_list_c(opl
, "chan", BX_SB16_FM_NCH
);
379 for (i
=0; i
<BX_SB16_FM_NCH
; i
++) {
380 sprintf(name
, "%d", i
);
381 item
= new bx_list_c(chan
, name
, 19);
382 new bx_shadow_num_c(item
, "nop", &OPL
.chan
[i
].nop
);
383 new bx_shadow_num_c(item
, "ncarr", &OPL
.chan
[i
].ncarr
);
384 new bx_shadow_num_c(item
, "opnum1", &OPL
.chan
[i
].opnum
[0]);
385 new bx_shadow_num_c(item
, "opnum2", &OPL
.chan
[i
].opnum
[1]);
386 new bx_shadow_num_c(item
, "opnum3", &OPL
.chan
[i
].opnum
[2]);
387 new bx_shadow_num_c(item
, "opnum4", &OPL
.chan
[i
].opnum
[3]);
388 new bx_shadow_num_c(item
, "freq", &OPL
.chan
[i
].freq
);
389 new bx_shadow_num_c(item
, "afreq", &OPL
.chan
[i
].afreq
);
390 new bx_shadow_num_c(item
, "midichan", &OPL
.chan
[i
].midichan
);
391 new bx_shadow_bool_c(item
, "needprogch", &OPL
.chan
[i
].needprogch
);
392 new bx_shadow_num_c(item
, "midinote", &OPL
.chan
[i
].midinote
);
393 new bx_shadow_bool_c(item
, "midion", &OPL
.chan
[i
].midion
);
394 new bx_shadow_num_c(item
, "midibend", &OPL
.chan
[i
].midibend
);
395 new bx_shadow_num_c(item
, "outputlevel1", &OPL
.chan
[i
].outputlevel
[0]);
396 new bx_shadow_num_c(item
, "outputlevel2", &OPL
.chan
[i
].outputlevel
[1]);
397 new bx_shadow_num_c(item
, "outputlevel3", &OPL
.chan
[i
].outputlevel
[2]);
398 new bx_shadow_num_c(item
, "outputlevel4", &OPL
.chan
[i
].outputlevel
[3]);
399 new bx_shadow_num_c(item
, "midivol", &OPL
.chan
[i
].midivol
);
401 new bx_shadow_num_c(list
, "mixer_regindex", &MIXER
.regindex
, BASE_HEX
);
402 bx_list_c
*mixer
= new bx_list_c(list
, "mixer_reg", BX_SB16_MIX_REG
);
403 for (i
=0; i
<BX_SB16_MIX_REG
; i
++) {
404 sprintf(name
, "0x%02x", i
);
405 new bx_shadow_num_c(mixer
, name
, &MIXER
.reg
[i
], BASE_HEX
);
407 bx_list_c
*emul
= new bx_list_c(list
, "emul", 2);
408 new bx_shadow_num_c(emul
, "remaps", &EMUL
.remaps
);
409 bx_list_c
*remap
= new bx_list_c(emul
, "remaplist", 256);
410 for (i
=0; i
<EMUL
.remaps
; i
++) {
411 sprintf(name
, "0x%02x", i
);
412 ins_map
= new bx_list_c(remap
, name
, 6);
413 new bx_shadow_num_c(ins_map
, "oldbankmsb", &EMUL
.remaplist
[i
].oldbankmsb
);
414 new bx_shadow_num_c(ins_map
, "oldbanklsb", &EMUL
.remaplist
[i
].oldbanklsb
);
415 new bx_shadow_num_c(ins_map
, "oldprogch", &EMUL
.remaplist
[i
].oldprogch
);
416 new bx_shadow_num_c(ins_map
, "newbankmsb", &EMUL
.remaplist
[i
].newbankmsb
);
417 new bx_shadow_num_c(ins_map
, "newbanklsb", &EMUL
.remaplist
[i
].newbanklsb
);
418 new bx_shadow_num_c(ins_map
, "newprogch", &EMUL
.remaplist
[i
].newprogch
);
422 void bx_sb16_c::after_restore_state(void)
427 // the timer functions
428 void bx_sb16_c::mpu_timer (void *this_ptr
)
430 ((bx_sb16_c
*) this_ptr
)->mpu401
.current_timer
++;
433 void bx_sb16_c::dsp_dmatimer(void *this_ptr
)
435 bx_sb16_c
*This
= (bx_sb16_c
*) this_ptr
;
437 // raise the DRQ line. It is then lowered by dsp_getsamplebyte()
438 // when the next byte has been received.
439 // However, don't do this if the next byte/word will fill up the
440 // output buffer and the output functions are not ready yet.
442 if ((BX_SB16_THIS wavemode
!= 1) ||
443 ((This
->dsp
.dma
.chunkindex
+ 1 < BX_SOUND_OUTPUT_WAVEPACKETSIZE
) &&
444 (This
->dsp
.dma
.count
> 0)) ||
445 (This
->output
->waveready() == BX_SOUND_OUTPUT_OK
)) {
446 if ((DSP
.dma
.bits
== 8) || (BX_SB16_DMAH
== 0)) {
447 DEV_dma_set_drq(BX_SB16_DMAL
, 1);
449 DEV_dma_set_drq(BX_SB16_DMAH
, 1);
454 void bx_sb16_c::opl_timer (void *this_ptr
)
456 ((bx_sb16_c
*) this_ptr
)->opl_timerevent();
459 // the various IO handlers
461 // The DSP/FM music part
463 // dsp_reset() resets the DSP after the sequence 1/0. Returns
464 // 0xaa on the data port
465 void bx_sb16_c::dsp_reset(Bit32u value
)
467 writelog(WAVELOG(4), "DSP Reset port write value %x", value
);
469 // just abort high speed mode if it is set
470 if (DSP
.dma
.highspeed
!= 0)
472 DSP
.dma
.highspeed
= 0;
473 writelog(WAVELOG(4), "High speed mode aborted");
477 if ((DSP
.resetport
== 1) && (value
== 0))
479 // 1-0 sequences to reset port, do one of the following:
480 // if in UART MIDI mode, abort it, don't reset
481 // if in Highspeed mode (not SB16!), abort it, don't reset
484 if (DSP
.midiuartmode
!= 0)
485 { // abort UART MIDI mode
486 DSP
.midiuartmode
= 0;
487 writelog(MIDILOG(4), "DSP UART MIDI mode aborted");
492 writelog(WAVELOG(4), "DSP resetting...");
494 if (DSP
.irqpending
!= 0)
496 DEV_pic_lower_irq(BX_SB16_IRQ
);
497 writelog(WAVELOG(4), "DSP reset: IRQ untriggered");
499 if (DSP
.dma
.mode
!= 0)
501 writelog(WAVELOG(4), "DSP reset: DMA aborted");
502 DSP
.dma
.mode
= 1; // no auto init anymore
509 DSP
.midiuartmode
= 0;
516 DSP
.dma
.issigned
= 0;
518 DSP
.dma
.highspeed
= 0;
519 DSP
.dma
.chunkindex
= 0;
521 DSP
.dataout
.reset(); // clear the buffers
524 DSP
.dataout
.put(0xaa); // acknowledge the reset
527 DSP
.resetport
= value
;
530 // dsp_dataread() reads the data port of the DSP
531 Bit32u
bx_sb16_c::dsp_dataread()
535 // if we are in MIDI UART mode, call the mpu401 part instead
536 if (DSP
.midiuartmode
!= 0)
537 value
= mpu_dataread();
540 // default behaviour: if none available, return last byte again
541 // if (DSP.dataout.empty() == 0)
542 DSP
.dataout
.get(&value
);
545 writelog(WAVELOG(4), "DSP Data port read, result = %x", value
);
550 // dsp_datawrite() writes a command or data byte to the data port
551 void bx_sb16_c::dsp_datawrite(Bit32u value
)
554 Bit8u index
= 0, mode
= 0, value8
= 0;
557 writelog(WAVELOG(4), "DSP Data port write, value %x", value
);
559 // in high speed mode, any data passed to DSP is a sample
560 if (DSP
.dma
.highspeed
!= 0)
562 dsp_getsamplebyte(value
);
566 // route information to mpu401 part if in MIDI UART mode
567 if (DSP
.midiuartmode
!= 0)
569 mpu_datawrite(value
);
573 if (DSP
.datain
.hascommand() == 1) // already a command pending, add to argument list
575 if (DSP
.datain
.put(value
) == 0)
577 writelog(WAVELOG(3), "DSP command buffer overflow for command %02x",
578 DSP
.datain
.currentcommand());
581 else // no command pending, set one up
583 bytesneeded
= 0; // find out how many arguments the command takes
585 { // all fallbacks intended!
649 DSP
.datain
.newcommand(value
, bytesneeded
);
652 if (DSP
.datain
.commanddone() == 1) // command is complete, process it
654 writelog(WAVELOG(4), "DSP command %x with %d arg bytes",
655 DSP
.datain
.currentcommand(), DSP
.datain
.bytes());
657 switch (DSP
.datain
.currentcommand())
659 // DSP commands - comments are the parameters for
660 // this command, and/or the output
662 // ASP commands (Advanced Signal Processor)
663 // undocumented (?), just from looking what an SB16 does
665 DSP
.datain
.get(&value8
);
669 DSP
.datain
.get(&value8
);
670 DSP
.datain
.get(&value8
);
674 DSP
.datain
.get(&index
);
675 DSP
.datain
.get(&value8
);
676 BX_SB16_THIS csp_reg
[index
] = value
;
680 DSP
.datain
.get(&index
);
681 DSP
.dataout
.put(BX_SB16_THIS csp_reg
[index
]);
687 DSP
.datain
.get(&value8
); // sample is ignored
690 // uncomp'd, normal DAC DMA
692 // 1,2: lo(length) hi(length)
693 DSP
.datain
.getw(&length
);
694 dsp_dma(0xc0, 0x00, length
, 0);
697 // 2-bit comp'd, normal DAC DMA, no ref byte
699 // 1,2: lo(length) hi(length)
700 DSP
.datain
.getw(&length
);
701 dsp_dma(0xc0, 0x00, length
, 2);
704 // 2-bit comp'd, normal DAC DMA, 1 ref byte
706 // 1,2: lo(length) hi(length)
707 DSP
.datain
.getw(&length
);
708 dsp_dma(0xc0, 0x00, length
, 2|8);
711 // uncomp'd, auto DAC DMA
714 dsp_dma(0xc4, 0x00, DSP
.dma
.blocklength
, 0);
717 // 2-bit comp'd, auto DAC DMA, 1 ref byte
720 dsp_dma(0xc4, 0x00, DSP
.dma
.blocklength
, 2|8);
726 DSP
.dataout
.put(0x80); // put a silence, for now.
729 // uncomp'd, normal ADC DMA
731 // 1,2: lo(length) hi(length)
732 DSP
.datain
.getw(&length
);
733 dsp_dma(0xc8, 0x00, length
, 0);
736 // uncomp'd, auto ADC DMA
739 dsp_dma(0xcc, 0x00, DSP
.dma
.blocklength
, 0);
742 // ? polling mode MIDI input
746 // ? interrupt mode MIDI input
750 // 0x34..0x37: UART mode MIDI output
753 // UART mode MIDI input/output
756 // UART polling mode MIDI IO with time stamp
759 // UART interrupt mode MIDI IO with time stamp
761 // Fallbacks intended - all set the midi uart mode
762 DSP
.midiuartmode
= 1;
767 DSP
.datain
.get(&value8
);
768 // route to mpu401 part
769 mpu_datawrite(value8
);
775 DSP
.datain
.get(&value8
);
776 DSP
.dma
.timeconstant
= value8
<< 8;
777 DSP
.dma
.samplerate
= (Bit32u
) 256000000L / ((Bit32u
) 65536L - (Bit32u
) DSP
.dma
.timeconstant
);
780 // set samplerate for input
782 // (fallback intended)
784 // set samplerate for output
786 // 1,2: hi(frq) lo(frq)
787 DSP
.datain
.getw1(&(DSP
.dma
.samplerate
));
788 DSP
.dma
.timeconstant
= 65536 - (Bit32u
) 256000000 / (Bit32u
) DSP
.dma
.samplerate
;
793 // 1,2: lo(blk len) hi(blk len)
794 DSP
.datain
.getw(&(DSP
.dma
.blocklength
));
797 // 4-bit comp'd, normal DAC DMA, no ref byte
799 // 1,2: lo(length) hi(length)
800 DSP
.datain
.getw(&length
);
801 dsp_dma(0xc0, 0x00, length
, 4);
804 // 4-bit comp'd, normal DAC DMA, 1 ref byte
806 // 1,2: lo(length) hi(length)
807 DSP
.datain
.getw(&length
);
808 dsp_dma(0xc0, 0x00, length
, 4|8);
811 // 3-bit comp'd, normal DAC DMA, no ref byte
813 // 1,2: lo(length) hi(length)
814 DSP
.datain
.getw(&length
);
815 dsp_dma(0xc0, 0x00, length
, 3);
818 // 3-bit comp'd, normal DAC DMA, 1 ref byte
820 // 1,2: lo(length) hi(length)
821 DSP
.datain
.getw(&length
);
822 dsp_dma(0xc0, 0x00, length
, 3|8);
825 // 4-bit comp'd, auto DAC DMA, 1 ref byte
828 dsp_dma(0xc4, 0x00, DSP
.dma
.blocklength
, 4|8);
831 // 3-bit comp'd, auto DAC DMA, 1 ref byte
834 dsp_dma(0xc4, 0x00, DSP
.dma
.blocklength
, 3|8);
839 // 1,2: lo(silence) hi(silence) (len in samples)
840 DSP
.datain
.getw(&length
);
841 // only handled for VOC output so far
842 if (BX_SB16_THIS wavemode
== 2)
844 Bit8u temparray
[3] = { length
& 0xff, length
>> 8, DSP
.dma
.timeconstant
>> 8 };
845 writevocblock(3, 3, temparray
, 0, NULL
);
849 // 8-bit auto DAC DMA, highspeed
852 dsp_dma(0xc4, 0x00, DSP
.dma
.blocklength
, 16);
855 // 8-bit normal DAC DMA, highspeed
858 dsp_dma(0xc0, 0x00, DSP
.dma
.blocklength
, 16);
861 // 8-bit auto ADC DMA, highspeed
864 dsp_dma(0xcc, 0x00, DSP
.dma
.blocklength
, 16);
867 case 0x99: // 8-bit normal DMA
869 dsp_dma(0xc8, 0x00, DSP
.dma
.blocklength
, 16);
872 // switch to mono for SBPro DAC/ADC
878 // switch to stereo for SBPro DAC/ADC
885 // 16 bit DAC/ADC DMA, general commands
905 // 8 bit DAC/ADC DMA, general commands
922 DSP
.datain
.get(&mode
);
923 DSP
.datain
.getw(&length
);
924 dsp_dma(DSP
.datain
.currentcommand(), mode
, length
, 0);
927 // pause 8 bit DMA transfer
930 if (DSP
.dma
.mode
!= 0)
946 // continue 8 bit DMA, see 0xd0
949 if (DSP
.dma
.mode
!= 0)
956 if (DSP
.dma
.mode
!= 0)
960 // continue 16 bit DMA, see 0xd5
963 if (DSP
.dma
.mode
!= 0)
967 // read speaker on/off (out ff=on, 00=off)
969 // none, o1: speaker; ff/00
970 DSP
.dataout
.put((DSP
.speaker
== 1)?0xff:0x00);
973 // stop 16 bit auto DMA
976 if (DSP
.dma
.mode
!= 0)
978 DSP
.dma
.mode
= 1; // no auto init anymore
983 // stop 8 bit auto DMA
986 if (DSP
.dma
.mode
!= 0)
988 DSP
.dma
.mode
= 1; // no auto init anymore
993 // DSP identification
995 DSP
.datain
.get(&value8
);
996 DSP
.dataout
.put(~value8
);
999 // get version, out 2 bytes (major, minor)
1001 // none, o1/2: version major.minor
1003 if (DSP
.dataout
.put(5) == 0)
1005 writelog(WAVELOG(3), "DSP version couldn't be written - buffer overflow");
1010 // none, output: Copyright string
1011 // the Windows driver needs the exact text, otherwise it
1012 // won't load. Same for diagnose.exe
1013 DSP
.dataout
.puts("COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.");
1014 DSP
.dataout
.put(0); // need extra string end
1017 // write test register
1019 DSP
.datain
.get(&DSP
.testreg
);
1022 // read test register
1024 DSP
.dataout
.put(DSP
.testreg
);
1027 // Trigger 8-bit IRQ
1029 DSP
.dataout
.put(0xaa);
1031 MIXER
.reg
[0x82] |= 1; // reg 82 shows the kind of IRQ
1032 DEV_pic_raise_irq(BX_SB16_IRQ
);
1035 // ??? - Win98 needs this
1037 DSP
.datain
.get(&value8
);
1040 DSP
.dataout
.put(0xff);
1043 DSP
.dataout
.put(0x07);
1046 DSP
.dataout
.put(0x38);
1049 DSP
.dataout
.put(0x00);
1055 writelog(WAVELOG(3), "unknown DSP command %x, ignored",
1056 DSP
.datain
.currentcommand());
1059 DSP
.datain
.clearcommand();
1064 // dsp_dma() initiates all kinds of dma transfers
1065 void bx_sb16_c::dsp_dma(Bit8u command
, Bit8u mode
, Bit16u length
, Bit8u comp
)
1070 // command: 8bit, 16bit, in/out, single/auto, fifo
1071 // mode: mono/stereo, signed/unsigned
1072 // (for info on command and mode see sound blaster programmer's manual,
1074 // length: number of samples - not number of bytes
1075 // comp: bit-coded are: type of compression; ref-byte; highspeed
1076 // D0..D2: 0=none, 2,3,4 bits ADPCM
1080 writelog(WAVELOG(4), "DMA initialized. Cmd %02x, mode %02x, length %d, comp %d",
1081 command
, mode
, length
, comp
);
1083 if ((command
>> 4) == 0xb) // 0xb? = 16 bit DMA
1088 else // 0xc? = 8 bit DMA
1094 // Prevent division by zero in some instances
1095 if (DSP
.dma
.samplerate
== 0)
1096 DSP
.dma
.samplerate
= 10752;
1098 DSP
.dma
.output
= 1 - (command
>> 3); // 1=output, 0=input
1099 DSP
.dma
.mode
= 1 + ((command
>> 2) & 1); // 0=none, 1=normal, 2=auto
1100 DSP
.dma
.fifo
= (command
>> 1) & 1; // ? not sure what this is
1102 DSP
.dma
.stereo
= (mode
>> 5) & 1;
1104 if (DSP
.dma
.stereo
!= 0)
1107 DSP
.dma
.blocklength
= length
;
1108 DSP
.dma
.issigned
= (mode
>> 4) & 1;
1109 DSP
.dma
.highspeed
= (comp
>> 4) & 1;
1111 DSP
.dma
.chunkindex
= 0;
1112 DSP
.dma
.chunkcount
= 0;
1114 Bit32u sampledatarate
= (Bit32u
) DSP
.dma
.samplerate
* (Bit32u
) DSP
.dma
.bps
;
1115 if ((DSP
.dma
.bits
== 16) && (BX_SB16_DMAH
!= 0)) {
1116 DSP
.dma
.count
= (DSP
.dma
.blocklength
+ 1) * (DSP
.dma
.bps
/ 2) - 1;
1117 DSP
.dma
.timer
= BX_SB16_THIS dmatimer
/ (sampledatarate
/ 2);
1119 DSP
.dma
.count
= (DSP
.dma
.blocklength
+ 1) * DSP
.dma
.bps
- 1;
1120 DSP
.dma
.timer
= BX_SB16_THIS dmatimer
/ sampledatarate
;
1123 writelog(WAVELOG(5), "DMA is %db, %dHz, %s, %s, mode %d, %s, %s, %d bps, %d usec/DMA",
1124 DSP
.dma
.bits
, DSP
.dma
.samplerate
, (DSP
.dma
.stereo
!= 0)?"stereo":"mono",
1125 (DSP
.dma
.output
== 1)?"output":"input", DSP
.dma
.mode
,
1126 (DSP
.dma
.issigned
== 1)?"signed":"unsigned",
1127 (DSP
.dma
.highspeed
== 1)?"highspeed":"normal speed",
1128 sampledatarate
, DSP
.dma
.timer
);
1130 DSP
.dma
.format
= DSP
.dma
.issigned
| ((comp
& 7) << 1) | ((comp
& 8) << 4);
1132 // write the output to the device/file
1133 if (DSP
.dma
.output
== 1) {
1134 if (BX_SB16_THIS wavemode
== 1) {
1135 if (DSP
.outputinit
== 0) {
1136 ret
= BX_SB16_OUTPUT
->openwaveoutput(SIM
->get_param_string(BXPN_SB16_WAVEFILE
)->getptr());
1137 if (ret
!= BX_SOUND_OUTPUT_OK
) {
1138 BX_SB16_THIS wavemode
= 0;
1139 writelog(WAVELOG(2), "Error: Could not open wave output device.");
1142 ret
= BX_SB16_OUTPUT
->startwaveplayback(DSP
.dma
.samplerate
, DSP
.dma
.bits
, DSP
.dma
.stereo
, DSP
.dma
.format
);
1143 if (ret
!= BX_SOUND_OUTPUT_OK
) {
1144 BX_SB16_THIS wavemode
= 0;
1145 writelog(WAVELOG(2), "Error: Could not start wave playback.");
1149 } else if ((BX_SB16_THIS wavemode
== 2) ||
1150 (BX_SB16_THIS wavemode
== 3)) {
1151 base
= (bx_list_c
*) SIM
->get_param(BXPN_SB16
);
1152 WAVEDATA
= fopen(SIM
->get_param_string("wavefile", base
)->getptr(),"wb");
1153 if (WAVEDATA
== NULL
) {
1154 writelog (WAVELOG(2), "Error opening file %s. Wavemode disabled.",
1155 SIM
->get_param_string("wavefile", base
)->getptr());
1156 BX_SB16_THIS wavemode
= 0;
1157 } else if (BX_SB16_THIS wavemode
== 2) {
1167 // dsp_enabledma(): Start the DMA timer and thus the transfer
1169 void bx_sb16_c::dsp_enabledma()
1171 bx_pc_system
.activate_timer(DSP
.timer_handle
, DSP
.dma
.timer
, 1);
1174 // dsp_disabledma(): Stop the DMA timer and thus the transfer, but don't abort it
1175 void bx_sb16_c::dsp_disabledma()
1177 bx_pc_system
.deactivate_timer(DSP
.timer_handle
);
1180 // dsp_bufferstatus() checks if the DSP is ready for data/commands
1181 Bit32u
bx_sb16_c::dsp_bufferstatus()
1183 Bit32u result
= 0x7f;
1185 // MSB set -> not ready for commands
1186 if (DSP
.datain
.full() == 1) result
|= 0x80;
1188 writelog(WAVELOG(4), "DSP Buffer status read, result %x", result
);
1193 // dsp_status() checks if the DSP is ready to send data
1194 Bit32u
bx_sb16_c::dsp_status()
1196 Bit32u result
= 0x7f;
1198 // read might be to acknowledge IRQ
1199 if (DSP
.irqpending
!= 0)
1201 MIXER
.reg
[0x82] &= (~0x01);
1202 writelog(WAVELOG(4), "8-bit DMA or SBMIDI IRQ acknowledged");
1203 if ((MIXER
.reg
[0x82] & 0x07) == 0) {
1205 DEV_pic_lower_irq(BX_SB16_IRQ
);
1209 // if buffer is not empty, there is data to be read
1210 if (DSP
.dataout
.empty() == 0) result
|= 0x80;
1212 writelog(WAVELOG(4), "DSP output status read, result %x", result
);
1217 // dsp_irq16ack() notifies that the 16bit DMA IRQ has been acknowledged
1218 Bit32u
bx_sb16_c::dsp_irq16ack()
1220 Bit32u result
= 0xff;
1222 if (DSP
.irqpending
!= 0)
1224 MIXER
.reg
[0x82] &= (~0x02);
1225 if ((MIXER
.reg
[0x82] & 0x07) == 0) {
1227 DEV_pic_lower_irq(BX_SB16_IRQ
);
1229 writelog(WAVELOG(4), "16-bit DMA IRQ acknowledged");
1232 writelog(WAVELOG(3), "16-bit DMA IRQ acknowledged but not active!");
1240 // highlevel input and output handlers - rerouting to/from file,device
1242 // get a wave packet from the input device (not supported yet)
1243 void bx_sb16_c::dsp_getwavepacket()
1245 writelog(WAVELOG(3), "DMA reads not supported. Returning silence.");
1247 // fill the buffer with silence. Watch for 16bit transfer and signed/unsigned
1249 // these are the two different bytes in 16bit transfer (both the same for 8bit)
1252 byteA
= 0x00; // compatible with all signed transfers
1255 if (DSP
.dma
.issigned
== 0)
1258 if (DSP
.dma
.bits
== 8)
1261 for (int i
= 0; i
< BX_SOUND_OUTPUT_WAVEPACKETSIZE
; i
++)
1262 DSP
.dma
.chunk
[i
] = ((i
& 1) == 0) ? byteA
: byteB
;
1264 DSP
.dma
.chunkcount
= BX_SOUND_OUTPUT_WAVEPACKETSIZE
;
1265 DSP
.dma
.chunkindex
= 0;
1268 // write a wave packet to the output device
1269 void bx_sb16_c::dsp_sendwavepacket()
1271 switch (BX_SB16_THIS wavemode
)
1274 BX_SB16_OUTPUT
->sendwavepacket(DSP
.dma
.chunkindex
, DSP
.dma
.chunk
);
1277 fwrite(DSP
.dma
.chunk
, 1, DSP
.dma
.chunkindex
, WAVEDATA
);
1280 Bit8u temparray
[12] =
1281 { DSP
.dma
.samplerate
& 0xff, DSP
.dma
.samplerate
>> 8, 0, 0,
1282 DSP
.dma
.bits
, DSP
.dma
.stereo
+ 1, 0, 0, 0, 0, 0, 0 };
1283 switch ((DSP
.dma
.format
>> 1) & 7)
1295 if (DSP
.dma
.bits
== 16)
1298 writevocblock(9, 12, temparray
, DSP
.dma
.chunkindex
, DSP
.dma
.chunk
);
1302 DSP
.dma
.chunkindex
= 0;
1305 // put a sample byte into the output buffer
1306 void bx_sb16_c::dsp_getsamplebyte(Bit8u value
)
1308 if (DSP
.dma
.chunkindex
< BX_SOUND_OUTPUT_WAVEPACKETSIZE
)
1309 DSP
.dma
.chunk
[DSP
.dma
.chunkindex
++] = value
;
1311 if (DSP
.dma
.chunkindex
>= BX_SOUND_OUTPUT_WAVEPACKETSIZE
)
1312 dsp_sendwavepacket();
1315 // read a sample byte from the input buffer
1316 Bit8u
bx_sb16_c::dsp_putsamplebyte()
1318 if (DSP
.dma
.chunkindex
>= DSP
.dma
.chunkcount
)
1319 dsp_getwavepacket();
1321 return DSP
.dma
.chunk
[DSP
.dma
.chunkindex
++];
1324 // called when the last byte of a DMA transfer has been received/sent
1325 void bx_sb16_c::dsp_dmadone()
1327 writelog(WAVELOG(4), "DMA transfer done, triggering IRQ");
1329 if ((DSP
.dma
.output
== 1) && (DSP
.dma
.mode
!= 2)) {
1330 dsp_sendwavepacket(); // flush the output
1332 if (BX_SB16_THIS wavemode
== 1) {
1333 BX_SB16_OUTPUT
->stopwaveplayback();
1334 } else if (BX_SB16_THIS wavemode
!= 0) {
1339 // generate the appropriate IRQ
1340 if (DSP
.dma
.bits
== 8)
1341 MIXER
.reg
[0x82] |= 1;
1343 MIXER
.reg
[0x82] |= 2;
1345 DEV_pic_raise_irq(BX_SB16_IRQ
);
1348 // if auto-DMA, reinitialize
1349 if (DSP
.dma
.mode
== 2)
1351 if ((DSP
.dma
.bits
== 16) && (BX_SB16_DMAH
!= 0)) {
1352 DSP
.dma
.count
= (DSP
.dma
.blocklength
+ 1) * (DSP
.dma
.bps
/ 2) - 1;
1354 DSP
.dma
.count
= (DSP
.dma
.blocklength
+ 1) * DSP
.dma
.bps
- 1;
1356 writelog(WAVELOG(4), "auto-DMA reinitializing to length %d", DSP
.dma
.count
);
1365 // now the actual transfer routines, called by the DMA controller
1366 // note that read = from application to soundcard (output),
1367 // and write = from soundcard to application (input)
1368 void bx_sb16_c::dma_read8(Bit8u
*data_byte
)
1370 DEV_dma_set_drq(BX_SB16_DMAL
, 0); // the timer will raise it again
1372 if (DSP
.dma
.count
% 100 == 0) // otherwise it's just too many lines of log
1373 writelog(WAVELOG(5), "Received 8-bit DMA %2x, %d remaining ",
1374 *data_byte
, DSP
.dma
.count
);
1377 dsp_getsamplebyte(*data_byte
);
1379 if (DSP
.dma
.count
== 0xffff) // last byte received
1383 void bx_sb16_c::dma_write8(Bit8u
*data_byte
)
1385 DEV_dma_set_drq(BX_SB16_DMAL
, 0); // the timer will raise it again
1389 *data_byte
= dsp_putsamplebyte();
1391 if (DSP
.dma
.count
% 100 == 0) // otherwise it's just too many lines of log
1392 writelog(WAVELOG(5), "Sent 8-bit DMA %2x, %d remaining ",
1393 *data_byte
, DSP
.dma
.count
);
1395 if (DSP
.dma
.count
== 0xffff) // last byte sent
1399 void bx_sb16_c::dma_read16(Bit16u
*data_word
)
1401 DEV_dma_set_drq(BX_SB16_DMAH
, 0); // the timer will raise it again
1403 if (DSP
.dma
.count
% 100 == 0) // otherwise it's just too many lines of log
1404 writelog(WAVELOG(5), "Received 16-bit DMA %04x, %d remaining ",
1405 *data_word
, DSP
.dma
.count
);
1409 dsp_getsamplebyte(*data_word
& 0xff);
1410 dsp_getsamplebyte(*data_word
>> 8);
1412 if (DSP
.dma
.count
== 0xffff) // last word received
1416 void bx_sb16_c::dma_write16(Bit16u
*data_word
)
1420 DEV_dma_set_drq(BX_SB16_DMAH
, 0); // the timer will raise it again
1424 byte1
= dsp_putsamplebyte();
1425 byte2
= dsp_putsamplebyte();
1427 // all input is in little endian
1428 *data_word
= byte1
| (byte2
<< 8);
1430 if (DSP
.dma
.count
% 100 == 0) // otherwise it's just too many lines of log
1431 writelog(WAVELOG(5), "Sent 16-bit DMA %4x, %d remaining ",
1432 *data_word
, DSP
.dma
.count
);
1434 if (DSP
.dma
.count
== 0xffff) // last word sent
1438 // the mixer, supported type is CT1745 (as in an SB16)
1439 void bx_sb16_c::mixer_writedata(Bit32u value
)
1443 // do some action depending on what register was written
1444 switch (MIXER
.regindex
)
1446 case 0: // initialize mixer
1447 writelog(BOTHLOG(4), "Initializing mixer...");
1448 MIXER
.reg
[0x04] = 0xcc;
1449 MIXER
.reg
[0x0a] = 0x00;
1450 MIXER
.reg
[0x22] = 0xcc;
1451 MIXER
.reg
[0x26] = 0xcc;
1452 MIXER
.reg
[0x28] = 0x00;
1453 MIXER
.reg
[0x2e] = 0x00;
1454 MIXER
.reg
[0x3c] = 0x1f;
1455 MIXER
.reg
[0x3d] = 0x15;
1456 MIXER
.reg
[0x3e] = 0x0b;
1457 for (i
=0x30; i
<=0x35; i
++)
1458 MIXER
.reg
[i
] = 0xc0;
1459 for (i
=0x36; i
<=0x3b; i
++)
1460 MIXER
.reg
[i
] = 0x00;
1461 for (i
=0x3f; i
<=0x43; i
++)
1462 MIXER
.reg
[i
] = 0x00;
1463 for (i
=0x44; i
<=0x47; i
++)
1464 MIXER
.reg
[i
] = 0x80;
1466 MIXER
.regindex
= 0; // next mixer register read is register 0
1469 case 0x04: // DAC level
1470 MIXER
.reg
[0x32] = (value
& 0xf0) | 0x08;
1471 MIXER
.reg
[0x33] = ((value
& 0x0f) << 4) | 0x08;
1474 case 0x0a: // microphone level
1475 MIXER
.reg
[0x3a] = (value
<< 5) | 0x18;
1478 case 0x22: // master volume
1479 MIXER
.reg
[0x30] = (value
& 0xf0) | 0x08;
1480 MIXER
.reg
[0x31] = ((value
& 0x0f) << 4) | 0x08;
1483 case 0x26: // FM level
1484 MIXER
.reg
[0x34] = (value
& 0xf0) | 0x08;
1485 MIXER
.reg
[0x35] = ((value
& 0x0f) << 4) | 0x08;
1488 case 0x28: // CD audio level
1489 MIXER
.reg
[0x36] = (value
& 0xf0) | 0x08;
1490 MIXER
.reg
[0x37] = ((value
& 0x0f) << 4) | 0x08;
1493 case 0x2e: // line in level
1494 MIXER
.reg
[0x38] = (value
& 0xf0) | 0x08;
1495 MIXER
.reg
[0x39] = ((value
& 0x0f) << 4) | 0x08;
1498 case 0x30: // master volume left
1499 MIXER
.reg
[0x22] &= 0x0f;
1500 MIXER
.reg
[0x22] |= (value
& 0xf0);
1503 case 0x31: // master volume right
1504 MIXER
.reg
[0x22] &= 0xf0;
1505 MIXER
.reg
[0x22] |= (value
>> 4);
1508 case 0x32: // DAC level left
1509 MIXER
.reg
[0x04] &= 0x0f;
1510 MIXER
.reg
[0x04] |= (value
& 0xf0);
1513 case 0x33: // DAC level right
1514 MIXER
.reg
[0x04] &= 0xf0;
1515 MIXER
.reg
[0x04] |= (value
>> 4);
1518 case 0x34: // FM level left
1519 MIXER
.reg
[0x26] &= 0x0f;
1520 MIXER
.reg
[0x26] |= (value
& 0xf0);
1523 case 0x35: // FM level right
1524 MIXER
.reg
[0x26] &= 0xf0;
1525 MIXER
.reg
[0x26] |= (value
>> 4);
1528 case 0x36: // CD audio level left
1529 MIXER
.reg
[0x28] &= 0x0f;
1530 MIXER
.reg
[0x28] |= (value
& 0xf0);
1533 case 0x37: // CD audio level right
1534 MIXER
.reg
[0x28] &= 0xf0;
1535 MIXER
.reg
[0x28] |= (value
>> 4);
1538 case 0x38: // line in level left
1539 MIXER
.reg
[0x2e] &= 0x0f;
1540 MIXER
.reg
[0x2e] |= (value
& 0xf0);
1543 case 0x39: // line in level right
1544 MIXER
.reg
[0x2e] &= 0xf0;
1545 MIXER
.reg
[0x2e] |= (value
>> 4);
1548 case 0x3a: // microphone level
1549 MIXER
.reg
[0x0a] = (value
>> 5);
1567 case 0x80: // IRQ mask
1568 case 0x81: // DMA mask
1569 MIXER
.reg
[MIXER
.regindex
] = value
;
1570 set_irq_dma(); // both 0x80 and 0x81 handled
1573 default: // ignore read-only registers
1578 MIXER
.reg
[MIXER
.regindex
] = value
;
1580 writelog(BOTHLOG(4), "mixer register %02x set to %02x",
1581 MIXER
.regindex
, MIXER
.reg
[MIXER
.regindex
]);
1584 Bit32u
bx_sb16_c::mixer_readdata()
1586 writelog(BOTHLOG(4), "read from mixer register %02x returns %02x",
1587 MIXER
.regindex
, MIXER
.reg
[MIXER
.regindex
]);
1588 return(MIXER
.reg
[MIXER
.regindex
]);
1591 void bx_sb16_c::mixer_writeregister(Bit32u value
)
1593 MIXER
.regindex
= value
;
1596 void bx_sb16_c::set_irq_dma()
1598 static bx_bool isInitialized
=0;
1600 int oldDMA8
, oldDMA16
;
1602 // set the IRQ according to the value in mixer register 0x80
1603 switch (MIXER
.reg
[0x80])
1619 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x80. IRQ set to %d",
1620 MIXER
.reg
[0x80], newirq
);
1621 MIXER
.reg
[0x80] = 2;
1623 if (newirq
!= BX_SB16_IRQ
) // a different IRQ was set
1625 if (BX_SB16_IRQ
> 0)
1626 DEV_unregister_irq(BX_SB16_IRQ
, "SB16");
1628 BX_SB16_IRQ
= newirq
;
1629 DEV_register_irq(BX_SB16_IRQ
, "SB16");
1632 // set the 8 bit DMA
1633 oldDMA8
=BX_SB16_DMAL
;
1634 switch (MIXER
.reg
[0x81] & 0x0f)
1647 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x81. DMA8 set to %d",
1648 MIXER
.reg
[0x81], BX_SB16_DMAL
);
1649 MIXER
.reg
[0x81] &= (~0x0f);
1650 MIXER
.reg
[0x81] |= (1 << BX_SB16_DMAL
);
1653 // Unregister the previous DMA if initialized
1654 if ((isInitialized
) && (oldDMA8
!= BX_SB16_DMAL
))
1655 DEV_dma_unregister_channel(oldDMA8
);
1657 // And register the new 8bits DMA Channel
1658 if ((!isInitialized
) || (oldDMA8
!= BX_SB16_DMAL
))
1659 DEV_dma_register_8bit_channel(BX_SB16_DMAL
, dma_read8
, dma_write8
, "SB16");
1661 // and the 16 bit DMA
1662 oldDMA16
=BX_SB16_DMAH
;
1663 switch (MIXER
.reg
[0x81] >> 4)
1666 BX_SB16_DMAH
= 0; // no 16-bit DMA
1679 writelog(BOTHLOG(3), "Bad value %02x in mixer register 0x81. DMA16 set to %d",
1680 MIXER
.reg
[0x81], BX_SB16_DMAH
);
1681 MIXER
.reg
[0x81] &= (~0xf0);
1682 // MIXER.reg[0x81] |= (1 << BX_SB16_DMAH);
1683 // no default 16 bit channel!
1686 // Unregister the previous DMA if initialized
1687 if ((isInitialized
) && (oldDMA16
!= 0) && (oldDMA16
!= BX_SB16_DMAH
))
1688 DEV_dma_unregister_channel(oldDMA16
);
1690 // And register the new 16bits DMA Channel
1691 if ((BX_SB16_DMAH
!= 0) && (oldDMA16
!= BX_SB16_DMAH
))
1692 DEV_dma_register_16bit_channel(BX_SB16_DMAH
, dma_read16
, dma_write16
, "SB16");
1694 // If not already initialized
1695 if(!isInitialized
) {
1698 writelog(BOTHLOG(1), "Resources set to I%d D%d H%d",
1699 BX_SB16_IRQ
, BX_SB16_DMAL
, BX_SB16_DMAH
);
1704 // now the MPU 401 part
1706 // the MPU 401 status port shows if input or output are ready
1707 // Note that the bits are inverse to their meaning
1709 Bit32u
bx_sb16_c::mpu_status()
1713 if ((MPU
.datain
.full() == 1) ||
1714 ((BX_SB16_THIS midimode
== 1) &&
1715 (BX_SB16_OUTPUT
->midiready() == BX_SOUND_OUTPUT_ERR
)))
1716 result
|= 0x40; // output not ready
1717 if (MPU
.dataout
.empty() == 1)
1718 result
|= 0x80; // no input available
1720 writelog(MIDILOG(4), "MPU status port, result %02x", result
);
1725 // the MPU 401 command port
1727 void bx_sb16_c::mpu_command(Bit32u value
)
1732 if (MPU
.cmd
.hascommand() == 1) // already a command pending, abort that one
1734 if ((MPU
.cmd
.currentcommand() != value
) ||
1735 (MPU
.cmd
.commanddone() == 0))
1736 // it's a different command, or the old one isn't done yet, abort it
1738 MPU
.cmd
.clearcommand();
1742 // if it's the same one, and we just completed the argument list,
1743 // we leave it as it is and process it here
1746 if (MPU
.cmd
.hascommand() == 0) // no command pending, set one up
1749 if ((value
>> 4) == 14) bytesneeded
= 1;
1750 MPU
.cmd
.newcommand(value
, bytesneeded
);
1753 if (MPU
.cmd
.commanddone() == 1) // command is complete, process it
1755 switch (MPU
.cmd
.currentcommand())
1758 writelog(MIDILOG(5), "MPU cmd: UART mode on");
1761 MPU
.singlecommand
=0;
1762 if (BX_SB16_IRQMPU
!= -1) {
1763 MIXER
.reg
[0x82] |= 4;
1764 DEV_pic_raise_irq(BX_SB16_IRQMPU
);
1769 writelog(MIDILOG(4), "MPU cmd: Master reset of device");
1770 MPU
.uartmode
=MPU
.forceuartmode
;
1771 MPU
.singlecommand
=0;
1772 for (i
=0; i
<16; i
++)
1779 MPU
.dataout
.reset();
1781 MPU
.midicmd
.reset();
1784 if (BX_SB16_IRQ != -1) {
1785 MIXER.reg[0x82] |= 4;
1786 BX_SB16_THIS devices->pic->trigger_irq(BX_SB16_IRQ);
1790 case 0xd0: // d0 and df: prefix for midi command
1791 case 0xdf: // like uart mode, but only a single command
1792 MPU
.singlecommand
= 1;
1793 writelog(MIDILOG(4), "MPU: prefix %02x received",
1794 MPU
.cmd
.currentcommand());
1797 writelog(MIDILOG(3), "MPU cmd: unknown command %02x ignored",
1798 MPU
.cmd
.currentcommand());
1802 // Need to put an MPU_ACK into the data port if command successful
1803 // we'll fake it even if we didn't process the command, so as to
1804 // allow detection of the MPU 401.
1805 if (MPU
.dataout
.put(0xfe) == 0)
1806 writelog(MIDILOG(3), "MPU_ACK error - output buffer full");
1807 MPU
.cmd
.clearcommand(); // clear the command from the buffer
1812 // MPU 401 data port/read: contains an MPU_ACK after receiving a command
1813 // Will contain other data as well when other than UART mode is supported
1815 Bit32u
bx_sb16_c::mpu_dataread()
1820 // also acknowledge IRQ?
1821 if (MPU
.irqpending
!= 0)
1824 MIXER
.reg
[0x82] &= (~4);
1825 if ((MIXER
.reg
[0x82] & 0x07) == 0)
1826 DEV_pic_lower_irq(BX_SB16_IRQMPU
);
1827 writelog(MIDILOG(4), "MPU IRQ acknowledged");
1830 if (MPU
.dataout
.get(&res8bit
) == 0) {
1831 writelog(MIDILOG(3), "MPU data port not ready - no data in buffer");
1835 result
= (Bit32u
) res8bit
;
1837 writelog(MIDILOG(4), "MPU data port, result %02x", result
);
1843 // MPU 401 data port/write: This is where the midi stream comes from,
1844 // as well as arguments to any pending command
1846 void bx_sb16_c::mpu_datawrite(Bit32u value
)
1848 writelog(MIDILOG(4), "write to MPU data port, value %02x", value
);
1850 if (MPU
.cmd
.hascommand() == 1)
1851 { // there is a command pending, add arguments to it
1852 if (MPU
.cmd
.put(value
) == 0)
1853 writelog(MIDILOG(3), "MPU Command arguments too long - buffer full");
1854 if (MPU
.cmd
.commanddone() == 1)
1855 BX_SB16_THIS
mpu_command(MPU
.cmd
.currentcommand());
1857 else if ((MPU
.uartmode
== 0) && (MPU
.singlecommand
== 0))
1859 // Hm? No UART mode, but still data? Maybe should send it
1860 // to the command port... Only SBMPU401.EXE does this...
1861 writelog(MIDILOG(4), "MPU Data %02x received but no UART mode. Assuming it's a command.", value
);
1865 else // no MPU command pending, in UART mode, this has to be midi data
1866 mpu_mididata(value
);
1869 // A byte of midi data has been received
1870 void bx_sb16_c::mpu_mididata(Bit32u value
)
1872 // first, find out if it is a midi command or midi data
1873 bx_bool ismidicommand
= 0;
1875 { // bit 8 usually denotes a midi command...
1877 if ((value
== 0xf7) && (MPU
.midicmd
.currentcommand() == 0xf0))
1878 // ...except if it is a continuing SYSEX message, then it just
1879 // denotes the end of a SYSEX chunk, not the start of a message
1881 ismidicommand
= 0; // first, it's not a command
1882 MPU
.midicmd
.newcommand(MPU
.midicmd
.currentcommand(),
1883 MPU
.midicmd
.bytes());
1884 // Then, set needed bytes to current buffer
1885 // because we didn't know the length before
1889 if (ismidicommand
== 1)
1890 { // this is a command, check if an old one is pending
1891 if (MPU
.midicmd
.hascommand() == 1)
1893 writelog(MIDILOG(3), "Midi command %02x incomplete, has %d of %d bytes.",
1894 MPU
.midicmd
.currentcommand(), MPU
.midicmd
.bytes(),
1895 MPU
.midicmd
.commandbytes());
1896 // write as much as we can. Should we do this?
1897 processmidicommand(0);
1898 // clear the pending command
1899 MPU
.midicmd
.clearcommand();
1900 MPU
.midicmd
.flush();
1903 // find the number of arguments to the command
1904 static const signed eventlength
[] = { 2, 2, 2, 2, 1, 1, 2, 255};
1905 // note - length 255 commands have unknown length
1906 MPU
.midicmd
.newcommand(value
, eventlength
[(value
& 0x70) >> 4]);
1908 else // no command, just arguments to the old command
1910 if (MPU
.midicmd
.hascommand() == 0)
1911 { // no command pending, ignore the data
1912 writelog(MIDILOG(3), "Midi data %02x received, but no command pending?", value
);
1916 // just some data to the command
1917 if (MPU
.midicmd
.put(value
) == 0)
1918 writelog(MIDILOG(3), "Midi buffer overflow!");
1919 if (MPU
.midicmd
.commanddone() == 1)
1921 // the command is complete, process it
1922 writelog(MIDILOG(5), "Midi command %02x complete, has %d bytes.",
1923 MPU
.midicmd
.currentcommand(), MPU
.midicmd
.bytes());
1924 processmidicommand(0);
1925 // and remove the command from the buffer
1926 MPU
.midicmd
.clearcommand();
1927 MPU
.midicmd
.flush();
1932 // The emulator port/read: See if commands were successful
1934 Bit32u
bx_sb16_c::emul_read()
1939 if (EMUL
.datain
.get(&res8bit
) == 0)
1941 writelog(3, "emulator port not ready - no data in buffer");
1944 else result
= (Bit32u
) res8bit
;
1946 writelog(4, "emulator port, result %02x", result
);
1951 // Emulator port/write: Changing instrument mapping etc.
1953 void bx_sb16_c::emul_write(Bit32u value
)
1957 writelog(4, "write to emulator port, value %02x", value
);
1959 if (EMUL
.dataout
.hascommand() == 0) // no command pending, set it up
1961 static signed char cmdlength
[] = { 0, 0, 4, 2, 6, 1, 0, 0, 1, 1, 0, 1};
1964 writelog(3, "emulator command %02x unknown, ignored.", value
);
1967 writelog(5, "emulator command %02x, needs %d arguments",
1968 value
, cmdlength
[value
]);
1969 EMUL
.dataout
.newcommand(value
, cmdlength
[value
]);
1970 EMUL
.datain
.reset();
1971 EMUL
.datain
.put(0xfe);
1974 EMUL
.dataout
.put(value
); // otherwise just add data
1976 if (EMUL
.dataout
.commanddone() == 1)
1977 { // process the command
1978 writelog(4, "executing emulator command %02x with %d arguments",
1979 EMUL
.dataout
.currentcommand(), EMUL
.dataout
.bytes());
1980 switch (EMUL
.dataout
.currentcommand())
1982 case 0: // reinit of emulator
1983 writelog(4, "Emulator reinitialized");
1985 EMUL
.dataout
.reset();
1986 EMUL
.datain
.reset();
1987 EMUL
.datain
.put(0xfe);
1989 case 1: // dummy command to reset state of emulator port
1990 // just give a few times to end any commands
1993 if (EMUL
.remaps
>= BX_SB16_PATCHTABLESIZE
) break;
1994 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldbankmsb
));
1995 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldbanklsb
));
1996 EMUL
.remaplist
[EMUL
.remaps
].oldprogch
= 0xff;
1997 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newbankmsb
));
1998 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newbanklsb
));
1999 EMUL
.remaplist
[EMUL
.remaps
].newprogch
= 0xff;
2001 writelog(4, "Map bank command received, from %d %d to %d %d",
2002 EMUL
.remaplist
[EMUL
.remaps
].oldbankmsb
,
2003 EMUL
.remaplist
[EMUL
.remaps
].oldbanklsb
,
2004 EMUL
.remaplist
[EMUL
.remaps
].newbankmsb
,
2005 EMUL
.remaplist
[EMUL
.remaps
].newbanklsb
);
2008 case 3: // map program change
2009 if (EMUL
.remaps
>= BX_SB16_PATCHTABLESIZE
) break;
2010 EMUL
.remaplist
[EMUL
.remaps
].oldbankmsb
= 0xff;
2011 EMUL
.remaplist
[EMUL
.remaps
].oldbanklsb
= 0xff;
2012 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldprogch
));
2013 EMUL
.remaplist
[EMUL
.remaps
].newbankmsb
= 0xff;
2014 EMUL
.remaplist
[EMUL
.remaps
].newbanklsb
= 0xff;
2015 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newprogch
));
2017 writelog(4, "Map program change received, from %d to %d",
2018 EMUL
.remaplist
[EMUL
.remaps
].oldprogch
,
2019 EMUL
.remaplist
[EMUL
.remaps
].newprogch
);
2022 case 4: // map bank and program change
2023 if (EMUL
.remaps
>= BX_SB16_PATCHTABLESIZE
) break;
2024 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldbankmsb
));
2025 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldbanklsb
));
2026 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].oldprogch
));
2027 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newbankmsb
));
2028 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newbanklsb
));
2029 EMUL
.dataout
.get (& (EMUL
.remaplist
[EMUL
.remaps
].newprogch
));
2031 writelog(4, "Complete remap received, from %d %d %d to %d %d %d",
2032 EMUL
.remaplist
[EMUL
.remaps
].oldbankmsb
,
2033 EMUL
.remaplist
[EMUL
.remaps
].oldbanklsb
,
2034 EMUL
.remaplist
[EMUL
.remaps
].oldprogch
,
2035 EMUL
.remaplist
[EMUL
.remaps
].newbankmsb
,
2036 EMUL
.remaplist
[EMUL
.remaps
].newbanklsb
,
2037 EMUL
.remaplist
[EMUL
.remaps
].newprogch
);
2041 case 5: EMUL
.dataout
.get(&value8
); // dump emulator state
2045 EMUL
.datain
.puts("SB16 Emulator for Bochs\n");
2048 EMUL
.datain
.puts("UART mode=%d (force=%d)\n",
2049 MPU
.uartmode
, MPU
.forceuartmode
);
2052 EMUL
.datain
.puts("timer=%d\n", MPU
.current_timer
);
2055 EMUL
.datain
.puts("%d remappings active\n", EMUL
.remaps
);
2058 EMUL
.datain
.puts("Resources are A%3x I%d D%d H%d T%d P%3x; Adlib at %3x\n",
2059 BX_SB16_IO
, BX_SB16_IRQ
, BX_SB16_DMAL
,
2060 BX_SB16_DMAH
, 6, BX_SB16_IOMPU
, BX_SB16_IOADLIB
);
2063 EMUL
.datain
.puts("Current OPL2/3 mode: %s",
2064 // ok, I admit that this is a bit ugly...
2065 (OPL
.mode
== single
)?"single OPL2 (OPL3 disabled)\n":
2066 (OPL
.mode
== adlib
)?"single OPL2 (no OPL3)\n":
2067 (OPL
.mode
== dual
)?"double OPL2\n":
2068 (OPL
.mode
== opl3
)?"OPL3\n":
2072 EMUL
.datain
.puts("no info. Only slots 0..5 have values.\n");
2076 case 6: // close midi and wave files and/or output
2077 if ((BX_SB16_THIS midimode
== 2) ||
2078 (BX_SB16_THIS midimode
== 3))
2080 if (BX_SB16_THIS midimode
== 2) finishmidifile();
2083 else if (BX_SB16_THIS midimode
== 1)
2084 BX_SB16_OUTPUT
->closemidioutput();
2085 BX_SB16_THIS midimode
= 0;
2087 if ((BX_SB16_THIS wavemode
== 2) ||
2088 (BX_SB16_THIS wavemode
== 3))
2090 if (BX_SB16_THIS wavemode
== 2) finishvocfile();
2094 BX_SB16_OUTPUT
->closewaveoutput();
2095 BX_SB16_THIS wavemode
= 0;
2097 case 7: // clear bank/program mappings
2099 writelog(4, "Bank/program mappings cleared.");
2101 case 8: // set force uart mode on/off
2102 EMUL
.dataout
.get(&value8
);
2103 MPU
.forceuartmode
= value8
;
2105 MPU
.uartmode
= MPU
.forceuartmode
;
2106 writelog(4, "Force UART mode = %d", MPU
.forceuartmode
);
2108 case 9: // enter specific OPL2/3 mode
2109 EMUL
.dataout
.get(&value8
);
2110 writelog(4, "Entering OPL2/3 mode %d", value8
);
2111 opl_entermode((bx_sb16_fm_mode
) value8
);
2113 case 10: // check emulator present
2114 EMUL
.datain
.put(0x55);
2116 case 11: // send data to midi device
2117 EMUL
.dataout
.get(&value8
);
2118 mpu_mididata(value8
);
2120 EMUL
.dataout
.clearcommand();
2121 EMUL
.dataout
.flush();
2125 // and finally the OPL (FM emulation) part
2127 // select a new operational mode for the FM part
2128 // this also serves as reset for the OPL chip
2129 void bx_sb16_c::opl_entermode(bx_sb16_fm_mode newmode
)
2133 // do nothing if the mode is unchanged
2134 if (OPL
.mode
== newmode
)
2137 // if the old mode was 0, and the new mode is 3, then
2138 // no reset is necessary, just set the flag
2139 if ((OPL
.mode
== single
) && (newmode
== opl3
))
2141 writelog(MIDILOG(4), "OPL3 mode enabled");
2146 writelog(MIDILOG(4), "Switching to OPL mode %d from %d", newmode
, OPL
.mode
);
2148 for (i
=0; i
<BX_SB16_FM_NCH
; i
++)
2153 if (OPL
.timer_running
!= 0)
2155 bx_pc_system
.deactivate_timer(OPL
.timer_handle
);
2156 OPL
.timer_running
= 0;
2159 OPL
.drumchannel
= 10;
2161 OPL
.midichannels
= 0xffff; // all channels but the drum channel available
2162 OPL
.midichannels
&= ~(1 << OPL
.drumchannel
);
2164 for (i
=0; i
<2; i
++) {
2165 OPL
.wsenable
[i
] = 0;
2168 OPL
.percmode
[i
] = 0;
2171 for (i
=0; i
<4; i
++) {
2173 OPL
.timerinit
[i
] = 0;
2176 // initialize the operators
2177 for (i
=0; i
<BX_SB16_FM_NOP
; i
++)
2178 for (j
=0; j
<BX_SB16_FM_OPB
; j
++)
2181 // TESTING for array bounds - compiler should bark if too high
2182 OPL
.oper
[BX_SB16_FM_NOP
-1][BX_SB16_FM_OPB
-1] = 0;
2184 // initialize the channels
2186 // first zero all values
2187 for (i
=0; i
<BX_SB16_FM_NCH
; i
++)
2189 OPL
.chan
[i
].nop
= 0;
2190 for (j
=0; j
<4; j
++) {
2191 OPL
.chan
[i
].opnum
[j
] = 0;
2192 OPL
.chan
[i
].outputlevel
[j
] = 0;
2194 OPL
.chan
[i
].freq
= 0;
2195 OPL
.chan
[i
].afreq
= 0;
2196 OPL
.chan
[i
].midichan
= 0xff;
2197 OPL
.chan
[i
].needprogch
= 0;
2198 OPL
.chan
[i
].midion
= 0;
2199 OPL
.chan
[i
].midinote
= 0;
2200 OPL
.chan
[i
].midibend
= 0;
2201 OPL
.chan
[i
].midivol
= 0;
2204 // assign the operators
2205 for (i
=0; i
<BX_SB16_FM_NCH
; i
++)
2207 OPL
.chan
[i
].nop
= 2;
2208 // who invented this absolutely insane operator grouping??
2209 // it's like this: (ch 9...17 as 0...8 but higher operators)
2210 // ch: 0 1 2 3 4 5 6 7 8
2211 // op1: 0 1 2 6 7 8 12 13 14
2212 // op2: 3 4 5 9 10 11 15 16 17
2213 OPL
.chan
[i
].opnum
[0] = i
+ ((int) (i
/ 3)) * 3;
2214 OPL
.chan
[i
].opnum
[1] = OPL
.chan
[i
].opnum
[0] + 3;
2217 // assign 4-op operators to the appropriate channels
2218 // note- they are not used unless .nop == 4
2219 for (i
=0; i
<6; i
++) {
2221 OPL
.chan
[j
].opnum
[2] = OPL
.chan
[j
+ 3].opnum
[0];
2222 OPL
.chan
[j
].opnum
[3] = OPL
.chan
[j
+ 3].opnum
[1];
2226 // this is called whenever one of the timer elapses
2227 void bx_sb16_c::opl_timerevent()
2229 for (int i
=0; i
<4; i
++) {
2230 if ((OPL
.tmask
[i
/2] & (1 << (i
% 2))) != 0)
2231 { // only running timers
2232 if ((OPL
.timer
[i
]--) == 0)
2233 { // overflow occured, set flags accordingly
2234 OPL
.timer
[i
] = OPL
.timerinit
[i
]; // reset the counter
2235 if ((OPL
.tmask
[i
/2] >> (6 - (i
% 2))) == 0) // set flags only if unmasked
2237 writelog(WAVELOG(5), "OPL Timer Interrupt: Chip %d, Timer %d", i
/2, 1 << (i
% 2));
2238 OPL
.tflag
[i
/2] |= 1 << (6 - (i
% 2)); // set the overflow flag
2239 OPL
.tflag
[i
/2] |= 1 << 7; // set the IRQ flag
2246 // return the status of one of the OPL2's, or the
2247 // base status of the OPL3
2248 Bit32u
bx_sb16_c::opl_status(int chipid
)
2250 Bit32u status
= OPL
.tflag
[chipid
];
2251 writelog(MIDILOG(5), "OPL status of chip %d is %02x", chipid
, status
);
2255 // set the register index for one of the OPL2's or the
2256 // base or advanced register index for the OPL3
2257 void bx_sb16_c::opl_index(Bit32u value
, int chipid
)
2259 OPL
.index
[chipid
] = value
;
2262 // write to the data port
2263 void bx_sb16_c::opl_data(Bit32u value
, int chipid
)
2265 int index
= OPL
.index
[chipid
];
2266 int opernum
= -1; // OPL3 operator number; 0..35
2267 int channum
= -1; // OPL3 channel number; 0..17
2268 int subopnum
= -1; // channel operator; 0..nop-1
2270 writelog(MIDILOG(4), "Write to OPL(%d) register %02x: %02x",
2271 chipid
, index
, value
);
2273 // first find out operator and/or channel numbers
2274 // case 0x20 ... 0x95: includes too many ports, but that is harmless
2275 // case 0xe0 ... 0xf5:
2276 if (((index
>=0x20) && (index
<=0x95)) ||
2277 ((index
>=0xe0) && (index
<=0xf5))) {
2279 // find the operator number. 0..17 on chip 1, 18..35 on chip 2
2281 // note, the numbers are not continuous (again...), so we need
2282 // this rather weird calculation
2283 opernum
= index
& 0x07;
2284 if (opernum
> 5) // invalid register, has no operator associated
2290 opernum
+= (index
& 0x18) * 6;
2291 if (opernum
> 17) // Operators 18+ have to be accessed on other address set
2298 opernum
+= BX_SB16_FM_NOP
/ 2;
2300 // find out the channel number, and which of the channel's operators this is
2301 channum
= opernum
% 3 + ((int) (opernum
/ 6)) * 3;
2304 if ((opernum
% 6) > 2) // second operator
2307 // if (channel - 3) is in a four-operator mode, that is really
2308 // what this operator belongs to
2310 if (OPL
.chan
[channum
- 3].nop
== 4)
2316 writelog(MIDILOG(5), "Is Channel %d, Oper %d, Subop %d",
2317 channum
, opernum
, subopnum
);
2319 else if ((index
>=0xa0) && (index
<=0xc8)) {
2321 channum
= index
& 0x0f;
2322 if (OPL
.chan
[channum
].nop
== 0)
2323 channum
= -1; // the channel is disabled
2324 writelog(MIDILOG(5), "Is channel %d", channum
);
2329 switch (index
& 0xff)
2331 // WSEnable and Test Register
2333 OPL
.wsenable
[chipid
] = (value
>> 5) & 1;
2334 if ((value
& 0x1f) != 0)
2335 writelog(MIDILOG(3), "Warning: Test Register set to %02x", value
& 0x1f);
2338 // the two timer counts
2341 OPL
.timerinit
[(index
- 2) + chipid
* 2] =
2342 OPL
.timer
[(index
- 2) + chipid
* 2] = value
;
2345 // if OPL2: timer masks
2346 // if OPL3: 4-operator modes
2348 if ((chipid
== 0) || (OPL
.mode
== dual
))
2349 opl_settimermask(value
, chipid
);
2351 opl_set4opmode(value
& 0x3f);
2354 // only OPL3: OPL3 enable
2358 if ((value
& 1) != 0)
2359 opl_entermode(opl3
);
2361 opl_entermode(single
);
2365 // Composite Sine Wave and Note-sel (ignored)
2368 writelog(MIDILOG(3),
2369 "Warning: write of %02x to CSW/Note-sel ignored", value
);
2372 // most importantly the percussion part
2374 opl_setpercussion(value
, chipid
);
2377 // the operator registers
2378 // case 0x20 ... 0x35:
2401 // case 0x60 ... 0x75:
2424 // case 0x80 ... 0x95:
2449 opl_changeop(channum
, opernum
, (index
/ 0x20) - 1, value
);
2452 // else let default: catch it
2454 // case 0x40 ... 0x55:
2479 opl_changeop(channum
, opernum
, 1, value
& 0xc0);
2481 opl_setvolume(channum
, subopnum
, value
& 0x3f);
2484 // else let default: catch it
2486 // case 0xe0 ... 0xf5:
2511 opl_changeop(channum
, opernum
, 5, value
& 0x07);
2514 // else let default: catch it
2516 // and the channel registers
2517 // case 0xa0 ... 0xa8:
2529 if (value
!= (Bit32u
)(OPL
.chan
[channum
].freq
& 0xff)) {
2530 OPL
.chan
[channum
].freq
&= 0xff00;
2531 OPL
.chan
[channum
].freq
|= value
;
2532 opl_setfreq(channum
);
2536 // else let default: catch it
2538 // case 0xb0 ... 0xb8:
2550 if ((value
& 0x1f) != ((Bit32u
)(OPL
.chan
[channum
].freq
>> 8) & 0x1f)) {
2551 OPL
.chan
[channum
].freq
&= 0x00ff;
2552 OPL
.chan
[channum
].freq
|= (value
& 0x1f) << 8;
2553 opl_setfreq(channum
);
2555 opl_keyonoff(channum
, (value
>> 5) & 1);
2558 // else let default: catch it
2561 // this is a channel access, but it belongs to the instrument
2562 // definition, so put it into value [4] of the channel's first operator
2563 // case 0xc0 ... 0xc8:
2576 if ((OPL
.oper
[OPL
.chan
[channum
].opnum
[0]][4] & 1) != (int)(value
& 1))
2579 opl_changeop(channum
, OPL
.chan
[channum
].opnum
[0], 4, value
& 0x3f);
2581 if (needchange
== 1)
2582 opl_setmodulation(channum
);
2585 // else let default: catch it
2588 writelog(MIDILOG(3), "Attempt to write %02x to unknown OPL(%d) register %02x",
2589 value
, chipid
, index
);
2594 // change a value of an operator
2595 void bx_sb16_c::opl_changeop(int channum
, int opernum
, int byte
, int value
)
2597 if (OPL
.oper
[opernum
][byte
] != value
) {
2598 OPL
.oper
[opernum
][byte
] = value
;
2599 OPL
.chan
[channum
].needprogch
= 1;
2603 // called for a write to the 4-operator mode register
2604 void bx_sb16_c::opl_set4opmode(int new4opmode
)
2606 int i
, channel1
, channel2
;
2608 writelog(MIDILOG(4), "Switching to 4-op mode %02x", new4opmode
);
2610 // every bit switches a 4-op channel-pairing on or off
2611 // 4-op mode is two channels combined into the first one
2612 for (i
= 0; i
<6; i
++)
2614 channel1
= i
+ (i
/ 3) * 6;
2615 channel2
= channel1
+ 3;
2617 if (((new4opmode
>> i
) & 1) != 0)
2618 { // enable 4-op mode
2619 opl_keyonoff(channel1
, 0);
2620 opl_keyonoff(channel2
, 0);
2622 OPL
.chan
[channel1
].nop
= 4;
2623 OPL
.chan
[channel2
].nop
= 0;
2625 OPL
.chan
[channel1
].needprogch
= 1;
2628 { // disable 4-op mode
2629 opl_keyonoff(channel1
, 0);
2631 OPL
.chan
[channel1
].nop
= 2;
2632 OPL
.chan
[channel2
].nop
= 2;
2634 OPL
.chan
[channel1
].needprogch
= 1;
2635 OPL
.chan
[channel2
].needprogch
= 1;
2640 // called for a write to port 4 of either chip
2641 void bx_sb16_c::opl_settimermask(int value
, int chipid
)
2643 if ((value
& 0x80) != 0) // reset IRQ and timer flags
2644 { // all other bits ignored!
2645 writelog(MIDILOG(5), "IRQ Reset called");
2646 OPL
.tflag
[chipid
] = 0;
2650 OPL
.tmask
[chipid
] = value
& 0x63;
2651 writelog(MIDILOG(5), "New timer mask for chip %d is %02x",
2652 chipid
, OPL
.tmask
[chipid
]);
2654 // do we have to activate or deactivate the timer?
2655 if (((value
& 0x03) != 0) ^ (OPL
.timer_running
!= 0))
2657 if ((value
& 0x03) != 0) // yes, it's different. Start or stop?
2659 writelog(MIDILOG(5), "Starting timers");
2660 bx_pc_system
.activate_timer(OPL
.timer_handle
, 0, 1);
2661 OPL
.timer_running
= 1;
2665 writelog(MIDILOG(5), "Stopping timers");
2666 bx_pc_system
.deactivate_timer(OPL
.timer_handle
);
2667 OPL
.timer_running
= 0;
2672 // called when the modulation mode of a channel changes
2673 void bx_sb16_c::opl_setmodulation(int channel
)
2675 int opernum
= OPL
.chan
[channel
].opnum
[0];
2677 if ((OPL
.chan
[channel
].nop
== 0) &&
2679 (OPL
.chan
[channel
].nop
== 4)) channel
-= 3;
2681 if (OPL
.chan
[channel
].nop
== 2)
2683 OPL
.chan
[channel
].ncarr
= (OPL
.oper
[opernum
][4] & 1) + 1;
2684 OPL
.chan
[channel
].needprogch
= 1;
2686 else if (OPL
.chan
[channel
].nop
== 4)
2688 int opernum2
= OPL
.chan
[channel
].opnum
[2];
2689 int modmode
= (OPL
.oper
[opernum
][4] & 1) |
2690 ((OPL
.oper
[opernum2
][4] & 1) >> 1);
2691 OPL
.chan
[channel
].ncarr
= modmode
+ 1 - (modmode
/ 2);
2692 OPL
.chan
[channel
].needprogch
= 1;
2696 // called for a write to register 0xbd, the percussion register
2697 void bx_sb16_c::opl_setpercussion(Bit8u value
, int chipid
)
2703 // called when a channel volume changes
2704 // opnum is which of the channel's operators had the change, not
2705 // the actual operator number. Thus, it's from 0..3.
2706 void bx_sb16_c::opl_setvolume(int channel
, int opnum
, int outlevel
)
2711 OPL
.chan
[channel
].midivol
= 127;
2715 // called when a frequency change is complete, to find out the
2716 // corresponding midi key and pitch bender values
2717 void bx_sb16_c::opl_setfreq(int channel
)
2722 // low-byte of freq: 8 bit F-Number, LSB's
2723 // high-byte of freq: [2 reserved][KEY-ON][3 block][2 F-Number MSB's]
2724 // [KEY-ON] is ignored by this function
2726 // the definition of the F-number is
2727 // F-Number = Frequency * 2**(20-block) / (49716 Hz)
2729 // Thus, the frequency can be calculated as
2730 // Frequency = F-Number / 2**(20-block) * 49716 Hz
2732 // (But remember that afreq is in 10^-3 Hz!)
2735 fnum
= OPL
.chan
[channel
].freq
& 0x3ff;
2736 block
= (OPL
.chan
[channel
].freq
>> 10) & 0x07;
2738 writelog(MIDILOG(5), "F-Num is %d, block is %d", fnum
, block
);
2741 const Bit32u freqbase
= 49716000; // const is better than #define if type is important
2743 // this is a bit messy to preserve accuracy as much as possible,
2744 // otherwise we might either lose precision, or the higher bits.
2745 realfreq
= ((freqbase
>> 4) * fnum
) >> (16 - block
);
2747 OPL
.chan
[channel
].afreq
= realfreq
;
2749 // now find out what MIDI key this corresponds to, and with what
2750 // pitch bender value... (the latter not implemented yet)
2751 int octave
=0; // 0: Octave from 523.2511 Hz; pos=higher, neg=lower
2752 int keynum
=0; // 0=C; 1=C#; 2=D; ...; 11=B
2754 if (realfreq
> 8175) { // 8.175 is smallest possible frequency
2755 const Bit32u freqC
= 523251; // Midi note 72; "C": 523.251 Hz
2756 Bit32u keyfreq
; // Frequency scaled to the octave from freqC to 2*freqC
2758 if (realfreq
> freqC
) {
2759 while ((realfreq
>> (++octave
)) > freqC
);
2760 keyfreq
= realfreq
>> (--octave
);
2762 while ((realfreq
<< (++octave
)) < freqC
);
2763 keyfreq
= realfreq
<< octave
;
2767 // this is a reasonable approximation for keyfreq /= 1.059463
2768 // (that value is 2**(1/12), which is the difference between two keys)
2769 while ((keyfreq
-= ((keyfreq
* 1000) / 17817)) > freqC
)
2776 OPL
.chan
[channel
].midinote
= (octave
+ 6) * 12 + keynum
;
2778 writelog(MIDILOG(5), "New frequency %.3f is key %d in octave %d; midi note %d",
2779 (float) realfreq
/1000.0, keynum
, octave
, OPL
.chan
[channel
].midinote
);
2782 // called when a note is possibly turned on or off
2783 void bx_sb16_c::opl_keyonoff(int channel
, bx_bool onoff
)
2786 Bit8u commandbytes
[3];
2788 if (OPL
.mode
== fminit
)
2791 // first check if there really is a change in the state
2792 if (onoff
== OPL
.chan
[channel
].midion
)
2795 OPL
.chan
[channel
].midion
= onoff
;
2797 // check if we have a midi channel, otherwise allocate one if possible
2798 if (OPL
.chan
[channel
].midichan
== 0xff) {
2799 for (i
=0; i
<16; i
++)
2800 if (((OPL
.midichannels
>> i
) & 1) != 0) {
2801 OPL
.chan
[channel
].midichan
= i
;
2802 OPL
.midichannels
&= ~(1 << i
); // mark channel as used
2803 OPL
.chan
[channel
].needprogch
= 1;
2805 if (OPL
.chan
[channel
].midichan
== 0xff)
2809 if (OPL
.chan
[channel
].needprogch
!= 0)
2810 opl_midichannelinit(channel
);
2812 commandbytes
[0] = OPL
.chan
[channel
].midichan
;
2813 commandbytes
[1] = OPL
.chan
[channel
].midinote
;
2814 commandbytes
[2] = 0;
2817 commandbytes
[0] |= 0x80; // turn it off
2819 commandbytes
[0] |= 0x90; // turn it on
2820 commandbytes
[2] = OPL
.chan
[channel
].midivol
;
2823 writemidicommand(commandbytes
[0], 2, & (commandbytes
[1]));
2826 // setup a midi channel
2827 void bx_sb16_c::opl_midichannelinit(int channel
)
2832 /* Handlers for the midi commands/midi file output */
2834 // Write the header of the midi file. Track length is 0x7fffffff
2835 // until we know how long it's really going to be
2837 void bx_sb16_c::initmidifile()
2841 Bit32u chunklen
; // all values in BIG Endian!
2844 Bit16u timecode
; // 0x80 + deltatimesperquarter << 8
2846 #ifdef BX_LITTLE_ENDIAN
2847 { "MTh", 0x06000000, 0, 0x0100, 0x8001 };
2849 { "MTh", 6, 0, 1, 0x180 };
2851 midiheader
.chunk
[3] = 'd';
2858 #ifdef BX_LITTLE_ENDIAN
2859 { "MTr", 0xffffff7f,
2861 { "MTr", 0x7fffffff,
2863 { 0x00,0xff,0x51,3,0x07,0xa1,0x20, // set tempo 120 (0x7a120 us per quarter)
2864 0x00,0xff,0x58,4,4,2,0x18,0x08 }}; // time sig 4/4
2865 trackheader
.chunk
[3] = 'k';
2867 fwrite(&midiheader
, 1, 14, MIDIDATA
);
2868 fwrite(&trackheader
, 1, 23, MIDIDATA
);
2871 // write the midi command to the midi file
2873 void bx_sb16_c::writemidicommand(int command
, int length
, Bit8u data
[])
2876 /* We need to determine the time elapsed since the last MIDI command */
2877 int deltatime
= currentdeltatime();
2879 /* Initialize output device if necessary and not done yet */
2880 if (BX_SB16_THIS midimode
== 1) {
2881 if (MPU
.outputinit
!= 1) {
2882 writelog(MIDILOG(4), "Initializing Midi output.");
2883 if (BX_SB16_OUTPUT
->openmidioutput(SIM
->get_param_string(BXPN_SB16_MIDIFILE
)->getptr()) == BX_SOUND_OUTPUT_OK
)
2887 if (MPU
.outputinit
!= 1) {
2888 writelog(MIDILOG(2), "Error: Couldn't open midi output. Midi disabled.");
2889 BX_SB16_THIS midimode
= 0;
2893 BX_SB16_OUTPUT
->sendmidicommand(deltatime
, command
, length
, data
);
2895 } else if ((BX_SB16_THIS midimode
== 2) ||
2896 (BX_SB16_THIS midimode
== 3)) {
2897 base
= (bx_list_c
*) SIM
->get_param(BXPN_SB16
);
2898 MIDIDATA
= fopen(SIM
->get_param_string("midifile", base
)->getptr(),"wb");
2899 if (MIDIDATA
== NULL
) {
2900 writelog (MIDILOG(2), "Error opening file %s. Midimode disabled.",
2901 SIM
->get_param_string("midifile", base
)->getptr());
2902 BX_SB16_THIS midimode
= 0;
2903 } else if (BX_SB16_THIS midimode
== 2) {
2908 if (BX_SB16_THIS midimode
< 2)
2911 if (BX_SB16_THIS midimode
== 2)
2912 writedeltatime(deltatime
);
2914 fputc(command
, MIDIDATA
);
2915 if ((command
== 0xf0) ||
2916 (command
== 0xf7)) // write event length for sysex/meta events
2917 writedeltatime(length
);
2919 fwrite(data
, 1, length
, MIDIDATA
);
2922 // determine how many delta times have passed since
2923 // this function was called last
2925 int bx_sb16_c::currentdeltatime()
2929 // counting starts at first access
2930 if (MPU
.last_delta_time
== 0xffffffff)
2931 MPU
.last_delta_time
= MPU
.current_timer
;
2933 deltatime
= MPU
.current_timer
- MPU
.last_delta_time
;
2934 MPU
.last_delta_time
= MPU
.current_timer
;
2939 // process the midi command stored in MPU.midicmd.to the midi driver
2941 void bx_sb16_c::processmidicommand(bx_bool force
)
2945 bx_bool needremap
= 0;
2947 channel
= MPU
.midicmd
.currentcommand() & 0xf;
2949 // we need to log bank changes and program changes
2950 if ((MPU
.midicmd
.currentcommand() >> 4) == 0xc)
2951 { // a program change
2952 value
= MPU
.midicmd
.peek(0);
2953 writelog(MIDILOG(1), "* ProgramChange channel %d to %d",
2955 MPU
.program
[channel
] = value
;
2958 else if ((MPU
.midicmd
.currentcommand() >> 4) == 0xb)
2959 { // a control change, could be a bank change
2960 if (MPU
.midicmd
.peek(0) == 0)
2961 { // bank select MSB
2962 value
= MPU
.midicmd
.peek(1);
2963 writelog(MIDILOG(1), "* BankSelectMSB (%x %x %x) channel %d to %d",
2964 MPU
.midicmd
.peek(0), MPU
.midicmd
.peek(1), MPU
.midicmd
.peek(2),
2966 MPU
.bankmsb
[channel
] = value
;
2969 else if (MPU
.midicmd
.peek(0) == 32)
2970 { // bank select LSB
2971 value
= MPU
.midicmd
.peek(1);
2972 writelog(MIDILOG(1), "* BankSelectLSB channel %d to %d",
2974 MPU
.banklsb
[channel
] = value
;
2979 Bit8u temparray
[256];
2981 while (MPU
.midicmd
.empty() == 0)
2982 MPU
.midicmd
.get(&(temparray
[i
++]));
2984 writemidicommand(MPU
.midicmd
.currentcommand(), i
, temparray
);
2986 // if single command, revert to command mode
2987 if (MPU
.singlecommand
!= 0)
2989 MPU
.singlecommand
= 0;
2991 // MPU.irqpending = 1;
2992 // BX_SB16_THIS devices->pic->trigger_irq(BX_SB16_IRQMPU);
2995 if ((force
== 0) && (needremap
== 1))
2996 // have to check the remap lists, and remap program change if necessary
2997 midiremapprogram(channel
);
3000 // check if a program change has to be remapped, and do it if necessary
3002 void bx_sb16_c::midiremapprogram(int channel
)
3004 int bankmsb
,banklsb
,program
;
3005 Bit8u commandbytes
[2];
3007 bankmsb
= MPU
.bankmsb
[channel
];
3008 banklsb
= MPU
.banklsb
[channel
];
3009 program
= MPU
.program
[channel
];
3011 for(int i
= 0; i
< EMUL
.remaps
; i
++)
3013 if (((EMUL
.remaplist
[i
].oldbankmsb
== bankmsb
) ||
3014 (EMUL
.remaplist
[i
].oldbankmsb
== 0xff)) &&
3015 ((EMUL
.remaplist
[i
].oldbanklsb
== banklsb
) ||
3016 (EMUL
.remaplist
[i
].oldbanklsb
== 0xff)) &&
3017 ((EMUL
.remaplist
[i
].oldprogch
== program
) ||
3018 (EMUL
.remaplist
[i
].oldprogch
== 0xff)))
3020 writelog(5, "Remapping instrument for channel %d", channel
);
3021 if ((EMUL
.remaplist
[i
].newbankmsb
!= bankmsb
) &&
3022 (EMUL
.remaplist
[i
].newbankmsb
!= 0xff))
3023 { // write control change bank msb
3024 MPU
.bankmsb
[channel
] = EMUL
.remaplist
[i
].newbankmsb
;
3025 commandbytes
[0] = 0;
3026 commandbytes
[1] = EMUL
.remaplist
[i
].newbankmsb
;
3027 writemidicommand(0xb0 | channel
, 2, commandbytes
);
3029 if ((EMUL
.remaplist
[i
].newbanklsb
!= banklsb
) &&
3030 (EMUL
.remaplist
[i
].newbanklsb
!= 0xff))
3031 { // write control change bank lsb
3032 MPU
.banklsb
[channel
] = EMUL
.remaplist
[i
].newbanklsb
;
3033 commandbytes
[0] = 32;
3034 commandbytes
[1] = EMUL
.remaplist
[i
].newbanklsb
;
3035 writemidicommand(0xb0 | channel
, 2, commandbytes
);
3037 if ((EMUL
.remaplist
[i
].newprogch
!= program
) &&
3038 (EMUL
.remaplist
[i
].newprogch
!= 0xff))
3039 { // write program change
3040 MPU
.program
[channel
] = EMUL
.remaplist
[i
].newprogch
;
3041 commandbytes
[0] = EMUL
.remaplist
[i
].newprogch
;
3042 writemidicommand(0xc0 | channel
, 1, commandbytes
);
3048 // convert a number into a delta time coded value
3049 int bx_sb16_c::converttodeltatime(Bit32u deltatime
, Bit8u value
[4])
3063 while ((deltatime
> 0) && (count
< 4)) // split into parts
3065 outbytes
[count
++] = deltatime
& 0x7f;
3068 for (i
=0; i
<count
; i
++) // reverse order and
3069 value
[i
] = outbytes
[count
- i
- 1] | 0x80; // set eighth bit on
3070 value
[count
- 1] &= 0x7f; // all but last byte
3075 // write a delta time coded value to the midi file
3076 void bx_sb16_c::writedeltatime(Bit32u deltatime
)
3080 int count
= converttodeltatime(deltatime
, outbytes
);
3082 for (int i
=0; i
<count
; i
++)
3083 fputc(outbytes
[i
], MIDIDATA
);
3087 // close the midi file, and set the track length accordingly
3089 void bx_sb16_c::finishmidifile()
3092 Bit8u delta
, statusbyte
, metaevent
, length
;
3093 } metatrackend
= { 0, 0xff, 0x2f, 0 };
3095 // Meta event track end (0xff 0x2f 0x00) plus leading delta time
3096 fwrite(&metatrackend
, 1, sizeof metatrackend
, MIDIDATA
);
3098 Bit32u tracklen
= ftell(MIDIDATA
);
3100 BX_PANIC (("ftell failed in finishmidifile"));
3102 BX_PANIC (("finishmidifile with track length too short"));
3103 tracklen
-= 22; // subtract the midi file and track header
3104 fseek(MIDIDATA
, 22 - 4, SEEK_SET
);
3105 // value has to be in big endian
3106 #ifdef BX_LITTLE_ENDIAN
3107 tracklen
= (tracklen
<< 24) | (tracklen
>> 24) |
3108 ((tracklen
& 0x00ff0000) >> 8) |
3109 ((tracklen
& 0x0000ff00) << 8);
3111 fwrite(&tracklen
, 4, 1, MIDIDATA
);
3115 /* Handlers for the voc file output */
3117 // Write the header of the voc file.
3119 void bx_sb16_c::initvocfile()
3123 Bit16u headerlen
; // All in LITTLE Endian!
3127 { "Creative Voice File",
3128 #ifdef BX_LITTLE_ENDIAN
3129 0x1a, 0x0114, 0x111f };
3131 0x1a00, 0x1401, 0x1f11 };
3134 vocheader
.id
[19] = 26; // Replace string end with 26
3136 fwrite(&vocheader
, 1, sizeof vocheader
, WAVEDATA
);
3139 // write one block to the voc file
3140 void bx_sb16_c::writevocblock(int block
,
3141 Bit32u headerlen
, Bit8u header
[],
3142 Bit32u datalen
, Bit8u data
[])
3148 writelog(WAVELOG(3), "VOC Block %d not recognized, ignored.", block
);
3152 fputc(block
, WAVEDATA
);
3154 i
= headerlen
+ datalen
;
3155 #ifdef BX_LITTLE_ENDIAN
3156 fwrite(&i
, 1, 3, WAVEDATA
); // write the length in 24-bit little endian
3158 Bit8u lengthbytes
[3];
3159 lengthbytes
[0] = i
& 0xff; i
>>= 8;
3160 lengthbytes
[1] = i
& 0xff; i
>>= 8;
3161 lengthbytes
[2] = i
& 0xff;
3162 fwrite(lengthbytes
, 1, 3, WAVEDATA
);
3164 writelog(WAVELOG(5), "Voc block %d; Headerlen %d; Datalen %d",
3165 block
, headerlen
, datalen
);
3167 fwrite(header
, 1, headerlen
, WAVEDATA
);
3169 fwrite(data
, 1, datalen
, WAVEDATA
);
3172 // close the voc file
3173 void bx_sb16_c::finishvocfile()
3175 fputc(0, WAVEDATA
); // blocktype 0: end block
3178 // static IO port read callback handler
3179 // redirects to non-static class handler to avoid virtual functions
3181 Bit32u
bx_sb16_c::read_handler(void *this_ptr
, Bit32u address
, unsigned io_len
)
3183 #if !BX_USE_SB16_SMF
3184 bx_sb16_c
*class_ptr
= (bx_sb16_c
*) this_ptr
;
3185 return class_ptr
->read(address
, io_len
);
3188 Bit32u
bx_sb16_c::read(Bit32u address
, unsigned io_len
)
3192 #endif // !BX_USE_SB16_SMF
3196 // 2x0: FM Music Status Port
3197 // 2x8 and 388 are aliases
3198 case BX_SB16_IO
+ 0x00:
3199 case BX_SB16_IO
+ 0x08:
3200 case BX_SB16_IOADLIB
+ 0x00:
3201 return opl_status(0);
3203 // 2x1: reserved (w: FM Music Data Port)
3204 // 2x9 and 389 are aliases
3205 case BX_SB16_IO
+ 0x01:
3206 case BX_SB16_IO
+ 0x09:
3207 case BX_SB16_IOADLIB
+ 0x01:
3210 // 2x2: Advanced Music Status Port
3211 // or (for SBPro1) FM Music Status Port 2
3213 case BX_SB16_IO
+ 0x02:
3214 case BX_SB16_IOADLIB
+ 0x02:
3215 return opl_status(1);
3217 // 2x3: reserved (w: Adv. FM Music Data Port)
3218 // or (for SBPro1) FM Music Data Port 2
3220 case BX_SB16_IO
+ 0x03:
3221 case BX_SB16_IOADLIB
+ 0x03:
3224 // 2x4: reserved (w: Mixer Register Port)
3225 case BX_SB16_IO
+ 0x04:
3228 // 2x5: Mixer Data Port
3229 case BX_SB16_IO
+ 0x05:
3230 return mixer_readdata();
3232 // 2x6: reserved (w: DSP Reset)
3233 case BX_SB16_IO
+ 0x06:
3237 case BX_SB16_IO
+ 0x07:
3240 // 2x8: FM Music Status Port (OPL-2)
3243 // 2x9: reserved (w: FM Music Data Port)
3246 // 2xa: DSP Read Data Port
3247 case BX_SB16_IO
+ 0x0a:
3248 return dsp_dataread();
3251 case BX_SB16_IO
+ 0x0b:
3254 // 2xc: DSP Buffer Status Port
3255 case BX_SB16_IO
+ 0x0c:
3256 return dsp_bufferstatus();
3259 case BX_SB16_IO
+ 0x0d:
3262 // 2xe: DSP Data Status Port
3263 case BX_SB16_IO
+ 0x0e:
3264 return dsp_status();
3266 // 2xf: DSP Acknowledge 16bit DMA IRQ
3267 case BX_SB16_IO
+ 0x0f:
3268 return dsp_irq16ack();
3270 // 3x0: MPU Data Port Read
3271 case BX_SB16_IOMPU
+ 0x00:
3272 return mpu_dataread();
3274 // 3x1: MPU Status Port
3275 case BX_SB16_IOMPU
+ 0x01:
3276 return mpu_status();
3279 case BX_SB16_IOMPU
+ 0x02:
3282 // 3x3: *Emulator* Port
3283 case BX_SB16_IOMPU
+ 0x03:
3288 // If we get here, the port wasn't valid
3289 writelog(3, "Read access to 0x%04x: unsupported port!", address
);
3294 // static IO port write callback handler
3295 // redirects to non-static class handler to avoid virtual functions
3297 void bx_sb16_c::write_handler(void *this_ptr
, Bit32u address
, Bit32u value
, unsigned io_len
)
3299 #if !BX_USE_SB16_SMF
3300 bx_sb16_c
*class_ptr
= (bx_sb16_c
*) this_ptr
;
3301 class_ptr
->write(address
, value
, io_len
);
3304 void bx_sb16_c::write(Bit32u address
, Bit32u value
, unsigned io_len
)
3308 #endif // !BX_USE_SB16_SMF
3312 // 2x0: FM Music Register Port
3313 // 2x8 and 388 are aliases
3314 case BX_SB16_IO
+ 0x00:
3315 case BX_SB16_IO
+ 0x08:
3316 case BX_SB16_IOADLIB
+ 0x00:
3317 opl_index(value
, 0);
3320 // 2x1: FM Music Data Port
3321 // 2x9 and 389 are aliases
3322 case BX_SB16_IO
+ 0x01:
3323 case BX_SB16_IO
+ 0x09:
3324 case BX_SB16_IOADLIB
+ 0x01:
3328 // 2x2: Advanced FM Music Register Port
3329 // or (for SBPro1) FM Music Register Port 2
3331 case BX_SB16_IO
+ 0x02:
3332 case BX_SB16_IOADLIB
+ 0x02:
3333 opl_index(value
, 1);
3336 // 2x3: Advanced FM Music Data Port
3337 // or (for SBPro1) FM Music Data Port 2
3339 case BX_SB16_IO
+ 0x03:
3340 case BX_SB16_IOADLIB
+ 0x03:
3344 // 2x4: Mixer Register Port
3345 case BX_SB16_IO
+ 0x04:
3346 mixer_writeregister(value
);
3349 // 2x5: Mixer Data Portr,
3350 case BX_SB16_IO
+ 0x05:
3351 mixer_writedata(value
);
3355 case BX_SB16_IO
+ 0x06:
3360 case BX_SB16_IO
+ 0x07:
3363 // 2x8: FM Music Register Port (OPL-2)
3366 // 2x9: FM Music Data Port
3369 // 2xa: reserved (r: DSP Data Port)
3370 case BX_SB16_IO
+ 0x0a:
3374 case BX_SB16_IO
+ 0x0b:
3377 // 2xc: DSP Write Command/Data
3378 case BX_SB16_IO
+ 0x0c:
3379 dsp_datawrite(value
);
3383 case BX_SB16_IO
+ 0x0d:
3386 // 2xe: reserved (r: DSP Buffer Status)
3387 case BX_SB16_IO
+ 0x0e:
3391 case BX_SB16_IO
+ 0x0f:
3394 // 3x0: MPU Command Port
3395 case BX_SB16_IOMPU
+ 0x00:
3396 mpu_datawrite(value
);
3399 // 3x1: MPU Data Port
3400 case BX_SB16_IOMPU
+ 0x01:
3405 case BX_SB16_IOMPU
+ 0x02:
3408 // 3x3: *Emulator* Port
3409 case BX_SB16_IOMPU
+ 0x03:
3414 // if we arrive here, the port is unsupported
3415 writelog(3, "Write access to 0x%04x (value = 0x%02x): unsupported port!",
3419 void bx_sb16_c::writelog(int loglev
, const char *str
, ...)
3421 // append a line to the log file, if desired
3422 if (BX_SB16_THIS loglevel
>= loglev
)
3424 fprintf(LOGFILE
, FMT_TICK
, bx_pc_system
.time_ticks());
3425 fprintf(LOGFILE
, " (%d) ", loglev
);
3428 vfprintf(LOGFILE
, str
, ap
);
3430 fprintf(LOGFILE
, "\n");
3435 // the round-robin FIFO buffers of the SB16
3436 bx_sb16_buffer::bx_sb16_buffer()
3438 length
= 0; // total bytes in buffer
3439 head
= 0; // pointer to next slot available for new data
3440 tail
= 0; // pointer to next slot to be read from
3441 buffer
= NULL
; // pointer to the actual data
3444 void bx_sb16_buffer::init(int bufferlen
)
3446 if (buffer
!= NULL
) // Was it initialized before?
3450 buffer
= new Bit8u
[length
];
3452 length
= 0; // This will be checked later
3457 void bx_sb16_buffer::reset()
3459 head
= 0; // Reset the pointers
3462 clearcommand(); // no current command set
3465 bx_sb16_buffer::~bx_sb16_buffer()
3474 // Report how many bytes are available
3475 int bx_sb16_buffer::bytes(void)
3478 return 0; // empty / not initialized
3480 int bytes
= head
- tail
;
3481 if (bytes
< 0) bytes
+= length
;
3485 // This puts one byte into the buffer
3486 bx_bool
bx_sb16_buffer::put(Bit8u data
)
3489 return 0; // buffer full
3491 buffer
[head
++] = data
; // Write data, and increase write pointer
3492 head
%= length
; // wrap it around so it stays inside the data
3494 return 1; // put was successful
3497 // This writes a formatted string to the buffer
3498 bx_bool
bx_sb16_buffer::puts(char *data
, ...)
3501 return 0; // invalid string
3503 //char string[length];
3507 string
= (char *) malloc(length
);
3511 vsprintf(string
, data
, ap
);
3514 if ((int) strlen(string
) >= length
)
3515 BX_PANIC(("bx_sb16_buffer: puts() too long!"));
3517 while (string
[index
] != 0)
3519 if (put((Bit8u
) string
[index
]) == 0)
3520 return 0; // buffer full
3526 // This returns if the buffer is full, i.e. if a put will fail
3527 bx_bool
bx_sb16_buffer::full(void)
3530 return 1; // not initialized
3532 if (((head
+ 1) % length
) == tail
)
3533 return 1; // buffer full
3535 return 0; // buffer has some space left
3538 // This reads the next available byte from the buffer
3539 bx_bool
bx_sb16_buffer::get(Bit8u
*data
)
3543 // Buffer is empty. Still, if it was initialized, return
3544 // the last byte again.
3546 (*data
) = buffer
[ (tail
- 1) % length
];
3547 return 0; // buffer empty
3550 (*data
) = buffer
[tail
++]; // read data and increase read pointer
3551 tail
%= length
; // and wrap it around to stay inside the data
3553 return 1; // get was successful
3556 // Read a word in lo/hi order
3557 bx_bool
bx_sb16_buffer::getw(Bit16u
*data
)
3565 *data
= (Bit16u
) dummy
;
3572 *data
= (Bit16u
) dummy
;
3574 *data
|= ((Bit16u
) dummy
) << 8;
3578 // Read a word in hi/lo order
3579 bx_bool
bx_sb16_buffer::getw1(Bit16u
*data
)
3587 *data
= ((Bit16u
) dummy
) << 8;
3594 *data
= ((Bit16u
) dummy
) << 8;
3596 *data
|= (Bit16u
) dummy
;
3600 // This returns if the buffer is empty, i.e. if a get will fail
3601 bx_bool
bx_sb16_buffer::empty(void)
3604 return 1; // not inialized
3607 return 1; // buffer empty
3609 return 0; // buffer contains data
3612 // Flushes the buffer
3613 void bx_sb16_buffer::flush(void)
3619 // Peeks ahead in the buffer
3620 // Warning: No checking if result is valid. Must call bytes() to check that!
3621 Bit8u
bx_sb16_buffer::peek(int offset
)
3623 return buffer
[(tail
+ offset
) % length
];
3626 // Set a new active command
3627 void bx_sb16_buffer::newcommand(Bit8u newcmd
, int bytes
)
3631 bytesneeded
= bytes
;
3634 // Return the currently active command
3635 Bit8u
bx_sb16_buffer::currentcommand(void)
3640 // Clear the active command
3641 void bx_sb16_buffer::clearcommand(void)
3648 // return if the command has received all necessary bytes
3649 bx_bool
bx_sb16_buffer::commanddone(void)
3651 if (hascommand() == 0)
3652 return 0; // no command pending - not done then
3654 if (bytes() >= bytesneeded
)
3655 return 1; // yes, it's done
3657 return 0; // no, it's not
3660 // return if there is a command pending
3661 bx_bool
bx_sb16_buffer::hascommand(void)
3666 int bx_sb16_buffer::commandbytes(void)
3671 // The dummy output functions. They don't do anything
3672 bx_sound_output_c::bx_sound_output_c(bx_sb16_c
*sb16
)
3677 bx_sound_output_c::~bx_sound_output_c()
3681 int bx_sound_output_c::waveready()
3683 return BX_SOUND_OUTPUT_OK
;
3686 int bx_sound_output_c::midiready()
3688 return BX_SOUND_OUTPUT_OK
;
3691 int bx_sound_output_c::openmidioutput(char *device
)
3694 return BX_SOUND_OUTPUT_OK
;
3697 int bx_sound_output_c::sendmidicommand(int delta
, int command
, int length
, Bit8u data
[])
3703 return BX_SOUND_OUTPUT_OK
;
3706 int bx_sound_output_c::closemidioutput()
3708 return BX_SOUND_OUTPUT_OK
;
3711 int bx_sound_output_c::openwaveoutput(char *device
)
3714 return BX_SOUND_OUTPUT_OK
;
3717 int bx_sound_output_c::startwaveplayback(int frequency
, int bits
, int stereo
, int format
)
3723 return BX_SOUND_OUTPUT_OK
;
3726 int bx_sound_output_c::sendwavepacket(int length
, Bit8u data
[])
3730 return BX_SOUND_OUTPUT_OK
;
3733 int bx_sound_output_c::stopwaveplayback()
3735 return BX_SOUND_OUTPUT_OK
;
3738 int bx_sound_output_c::closewaveoutput()
3740 return BX_SOUND_OUTPUT_OK
;
3743 // runtime parameter handler
3744 Bit64s
bx_sb16_c::sb16_param_handler(bx_param_c
*param
, int set
, Bit64s val
)
3747 char pname
[BX_PATHNAME_LEN
];
3748 param
->get_param_path(pname
, BX_PATHNAME_LEN
);
3749 if (!strcmp(pname
, BXPN_SB16_DMATIMER
)) {
3750 BX_SB16_THIS dmatimer
= (Bit32u
)val
;
3751 } else if (!strcmp(pname
, BXPN_SB16_LOGLEVEL
)) {
3752 BX_SB16_THIS loglevel
= (int)val
;
3754 BX_PANIC(("sb16_param_handler called with unexpected parameter '%s'", pname
));
3760 #endif /* if BX_SUPPORT_SB16 */