SandboXP

Форк
0
/
sb16.js 
1857 строк · 49.0 Кб
1
"use strict";
2

3
// Useful documentation, articles, and source codes for reference:
4
// ===============================================================
5
//
6
// Official Hardware Programming Guide
7
// -> https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
8
//
9
// Official Yamaha YMF262 Manual
10
// -> http://map.grauw.nl/resources/sound/yamaha_ymf262.pdf
11
//
12
// OPL3 Programming Guide
13
// -> http://www.fit.vutbr.cz/~arnost/opl/opl3.html
14
//
15
// DOSBox
16
// -> https://sourceforge.net/p/dosbox/code-0/HEAD/tree/dosbox/branches/mamesound/src/hardware/sblaster.cpp
17
// -> https://github.com/duganchen/dosbox/blob/master/src/hardware/sblaster.cpp
18
// -> https://github.com/joncampbell123/dosbox-x/blob/master/src/hardware/sblaster.cpp
19
//
20
// QEMU
21
// -> https://github.com/qemu/qemu/blob/master/hw/audio/sb16.c
22
// -> https://github.com/hackndev/qemu/blob/master/hw/sb16.c
23
//
24
// VirtualBox
25
// -> https://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/Audio/DevSB16.cpp
26
// -> https://github.com/mdaniel/virtualbox-org-svn-vbox-trunk/blob/master/src/VBox/Devices/Audio/DevSB16.cpp
27

28
var
29

30
    // Used for drivers to identify device (DSP command 0xE3).
31
/** @const */ DSP_COPYRIGHT = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.",
32

33
    // Value of the current DSP command that indicates that the
34
    // next command/data write in port 2xC should be interpreted
35
    // as a command number.
36
/** @const */ DSP_NO_COMMAND = 0,
37

38
    // Size (bytes) of the DSP write/read buffers
39
/** @const */ DSP_BUFSIZE = 64,
40

41
    // Size (bytes) of the buffers containing floating point linear PCM audio.
42
/** @const */ DSP_DACSIZE = 65536,
43

44
    // Size (bytes) of the buffer in which DMA transfers are temporarily
45
    // stored before being processed.
46
/** @const */ SB_DMA_BUFSIZE = 65536,
47

48
    // Number of samples to attempt to retrieve per transfer.
49
/** @const */ SB_DMA_BLOCK_SAMPLES = 1024,
50

51
    // Usable DMA channels.
52
/** @const */ SB_DMA0 = 0,
53
/** @const */ SB_DMA1 = 1,
54
/** @const */ SB_DMA3 = 3,
55
/** @const */ SB_DMA5 = 5,
56
/** @const */ SB_DMA6 = 6,
57
/** @const */ SB_DMA7 = 7,
58

59
    // Default DMA channels.
60
/** @const */ SB_DMA_CHANNEL_8BIT = SB_DMA1,
61
/** @const */ SB_DMA_CHANNEL_16BIT = SB_DMA5,
62

63
    // Usable IRQ channels.
64
/** @const */ SB_IRQ2 = 2,
65
/** @const */ SB_IRQ5 = 5,
66
/** @const */ SB_IRQ7 = 7,
67
/** @const */ SB_IRQ10 = 10,
68

69
    // Default IRQ channel.
70
/** @const */ SB_IRQ = SB_IRQ5,
71

72
    // Indices to the irq_triggered register.
73
/** @const */ SB_IRQ_8BIT = 0x1,
74
/** @const */ SB_IRQ_16BIT = 0x2,
75
/** @const */ SB_IRQ_MIDI = 0x1,
76
/** @const */ SB_IRQ_MPU = 0x4;
77

78

79
// Probably less efficient, but it's more maintainable, instead
80
// of having a single large unorganised and decoupled table.
81
var DSP_COMMAND_SIZES = new Uint8Array(256);
82
var DSP_COMMAND_HANDLERS = [];
83
var MIXER_READ_HANDLERS = [];
84
var MIXER_WRITE_HANDLERS = [];
85
var MIXER_REGISTER_IS_LEGACY = new Uint8Array(256);
86
var FM_HANDLERS = [];
87

88

89
/**
90
 * Sound Blaster 16 Emulator, or so it seems.
91
 * @constructor
92
 * @param {CPU} cpu
93
 * @param {BusConnector} bus
94
 */
95
function SB16(cpu, bus)
96
{
97
    /** @const @type {CPU} */
98
    this.cpu = cpu;
99

100
    /** @const @type {BusConnector} */
101
    this.bus = bus;
102

103
    // I/O Buffers.
104
    this.write_buffer = new ByteQueue(DSP_BUFSIZE);
105
    this.read_buffer = new ByteQueue(DSP_BUFSIZE);
106
    this.read_buffer_lastvalue = 0;
107

108
    // Current DSP command info.
109
    this.command = DSP_NO_COMMAND;
110
    this.command_size = 0;
111

112
    // Mixer.
113
    this.mixer_current_address = 0;
114
    this.mixer_registers = new Uint8Array(256);
115
    this.mixer_reset();
116

117
    // Dummy status and test registers.
118
    this.dummy_speaker_enabled = false;
119
    this.test_register = 0;
120

121
    // DSP state.
122
    this.dsp_highspeed = false;
123
    this.dsp_stereo = false;
124
    this.dsp_16bit = false;
125
    this.dsp_signed = false;
126

127
    // DAC buffer.
128
    // The final destination for audio data before being sent off
129
    // to Web Audio APIs.
130
    // Format:
131
    // Floating precision linear PCM, nominal between -1 and 1.
132
    this.dac_buffers = [
133
      new FloatQueue(DSP_DACSIZE),
134
      new FloatQueue(DSP_DACSIZE),
135
    ];
136

137
    // Direct Memory Access transfer info.
138
    this.dma = cpu.devices.dma;
139
    this.dma_sample_count = 0;
140
    this.dma_bytes_count = 0;
141
    this.dma_bytes_left = 0;
142
    this.dma_bytes_block = 0;
143
    this.dma_irq = 0;
144
    this.dma_channel = 0;
145
    this.dma_channel_8bit = SB_DMA_CHANNEL_8BIT;
146
    this.dma_channel_16bit = SB_DMA_CHANNEL_16BIT;
147
    this.dma_autoinit = false;
148
    this.dma_buffer = new ArrayBuffer(SB_DMA_BUFSIZE);
149
    this.dma_buffer_int8 = new Int8Array(this.dma_buffer);
150
    this.dma_buffer_uint8 = new Uint8Array(this.dma_buffer);
151
    this.dma_buffer_int16 = new Int16Array(this.dma_buffer);
152
    this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer);
153
    this.dma_syncbuffer = new SyncBuffer(this.dma_buffer);
154
    this.dma_waiting_transfer = false;
155
    this.dma_paused = false;
156
    this.sampling_rate = 22050;
157
    bus.send("dac-tell-sampling-rate", this.sampling_rate);
158
    this.bytes_per_sample = 1;
159

160
    // DMA identification data.
161
    this.e2_value = 0xAA;
162
    this.e2_count = 0;
163

164
    // ASP data: not understood by me.
165
    this.asp_registers = new Uint8Array(256);
166

167
    // MPU.
168
    this.mpu_read_buffer = new ByteQueue(DSP_BUFSIZE);
169
    this.mpu_read_buffer_lastvalue = 0;
170

171
    // FM Synthesizer.
172
    this.fm_current_address0 = 0;
173
    this.fm_current_address1 = 0;
174
    this.fm_waveform_select_enable = false;
175

176
    // Interrupts.
177
    this.irq = SB_IRQ;
178
    this.irq_triggered = new Uint8Array(0x10);
179

180
    // IO Ports.
181
    // http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#DSPPorts
182
    // https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
183

184
    cpu.io.register_read_consecutive(0x220, this,
185
        this.port2x0_read, this.port2x1_read, this.port2x2_read, this.port2x3_read);
186
    cpu.io.register_read_consecutive(0x388, this,
187
        this.port2x0_read, this.port2x1_read);
188

189
    cpu.io.register_read_consecutive(0x224, this,
190
        this.port2x4_read, this.port2x5_read);
191

192
    cpu.io.register_read(0x226, this, this.port2x6_read);
193
    cpu.io.register_read(0x227, this, this.port2x7_read);
194
    cpu.io.register_read(0x228, this, this.port2x8_read);
195
    cpu.io.register_read(0x229, this, this.port2x9_read);
196

197
    cpu.io.register_read(0x22A, this, this.port2xA_read);
198
    cpu.io.register_read(0x22B, this, this.port2xB_read);
199
    cpu.io.register_read(0x22C, this, this.port2xC_read);
200
    cpu.io.register_read(0x22D, this, this.port2xD_read);
201

202
    cpu.io.register_read_consecutive(0x22E, this,
203
        this.port2xE_read, this.port2xF_read);
204

205
    cpu.io.register_write_consecutive(0x220, this,
206
        this.port2x0_write, this.port2x1_write, this.port2x2_write, this.port2x3_write);
207
    cpu.io.register_write_consecutive(0x388, this,
208
        this.port2x0_write, this.port2x1_write);
209

210
    cpu.io.register_write_consecutive(0x224, this,
211
        this.port2x4_write, this.port2x5_write);
212

213
    cpu.io.register_write(0x226, this, this.port2x6_write);
214
    cpu.io.register_write(0x227, this, this.port2x7_write);
215

216
    cpu.io.register_write_consecutive(0x228, this,
217
        this.port2x8_write, this.port2x9_write);
218

219
    cpu.io.register_write(0x22A, this, this.port2xA_write);
220
    cpu.io.register_write(0x22B, this, this.port2xB_write);
221
    cpu.io.register_write(0x22C, this, this.port2xC_write);
222
    cpu.io.register_write(0x22D, this, this.port2xD_write);
223
    cpu.io.register_write(0x22E, this, this.port2xE_write);
224
    cpu.io.register_write(0x22F, this, this.port2xF_write);
225

226
    cpu.io.register_read_consecutive(0x330, this, this.port3x0_read, this.port3x1_read);
227
    cpu.io.register_write_consecutive(0x330, this, this.port3x0_write, this.port3x1_write);
228

229
    this.dma.on_unmask(this.dma_on_unmask, this);
230

231
    bus.register("dac-request-data", function()
232
    {
233
        this.dac_handle_request();
234
    }, this);
235
    bus.register("speaker-has-initialized", function()
236
    {
237
        this.mixer_reset();
238
    }, this);
239
    bus.send("speaker-confirm-initialized");
240

241
    this.dsp_reset();
242
}
243

244
//
245
// General
246
//
247

248
SB16.prototype.dsp_reset = function()
249
{
250
    this.write_buffer.clear();
251
    this.read_buffer.clear();
252

253
    this.command = DSP_NO_COMMAND;
254
    this.command_size = 0;
255

256
    this.dummy_speaker_enabled = false;
257
    this.test_register = 0;
258

259
    this.dsp_highspeed = false;
260
    this.dsp_stereo = false;
261
    this.dsp_16bit = false;
262
    this.dsp_signed = false;
263

264
    this.dac_buffers[0].clear();
265
    this.dac_buffers[1].clear();
266

267
    this.dma_sample_count = 0;
268
    this.dma_bytes_count = 0;
269
    this.dma_bytes_left = 0;
270
    this.dma_bytes_block = 0;
271
    this.dma_irq = 0;
272
    this.dma_channel = 0;
273
    this.dma_autoinit = false;
274
    this.dma_buffer_uint8.fill(0);
275
    this.dma_waiting_transfer = false;
276
    this.dma_paused = false;
277

278
    this.e2_value = 0xAA;
279
    this.e2_count = 0;
280

281
    this.sampling_rate = 22050;
282
    this.bytes_per_sample = 1;
283

284
    this.lower_irq(SB_IRQ_8BIT);
285
    this.irq_triggered.fill(0);
286

287
    this.asp_registers.fill(0);
288
    this.asp_registers[5] = 0x01;
289
    this.asp_registers[9] = 0xF8;
290
};
291

292
SB16.prototype.get_state = function()
293
{
294
    var state = [];
295

296
    // state[0] = this.write_buffer;
297
    // state[1] = this.read_buffer;
298
    state[2] = this.read_buffer_lastvalue;
299

300
    state[3] = this.command;
301
    state[4] = this.command_size;
302

303
    state[5] = this.mixer_current_address;
304
    state[6] = this.mixer_registers;
305

306
    state[7] = this.dummy_speaker_enabled;
307
    state[8] = this.test_register;
308

309
    state[9] = this.dsp_highspeed;
310
    state[10] = this.dsp_stereo;
311
    state[11] = this.dsp_16bit;
312
    state[12] = this.dsp_signed;
313

314
    // state[13] = this.dac_buffers;
315
    //state[14]
316

317
    state[15] = this.dma_sample_count;
318
    state[16] = this.dma_bytes_count;
319
    state[17] = this.dma_bytes_left;
320
    state[18] = this.dma_bytes_block;
321
    state[19] = this.dma_irq;
322
    state[20] = this.dma_channel;
323
    state[21] = this.dma_channel_8bit;
324
    state[22] = this.dma_channel_16bit;
325
    state[23] = this.dma_autoinit;
326
    state[24] = this.dma_buffer_uint8;
327
    state[25] = this.dma_waiting_transfer;
328
    state[26] = this.dma_paused;
329
    state[27] = this.sampling_rate;
330
    state[28] = this.bytes_per_sample;
331

332
    state[29] = this.e2_value;
333
    state[30] = this.e2_count;
334

335
    state[31] = this.asp_registers;
336

337
    // state[32] = this.mpu_read_buffer;
338
    state[33] = this.mpu_read_buffer_last_value;
339

340
    state[34] = this.irq;
341
    state[35] = this.irq_triggered;
342
    //state[36]
343

344
    return state;
345
};
346

347
SB16.prototype.set_state = function(state)
348
{
349
    // this.write_buffer = state[0];
350
    // this.read_buffer = state[1];
351
    this.read_buffer_lastvalue = state[2];
352

353
    this.command = state[3];
354
    this.command_size = state[4];
355

356
    this.mixer_current_address = state[5];
357
    this.mixer_registers = state[6];
358
    this.mixer_full_update();
359

360
    this.dummy_speaker_enabled = state[7];
361
    this.test_register = state[8];
362

363
    this.dsp_highspeed = state[9];
364
    this.dsp_stereo = state[10];
365
    this.dsp_16bit = state[11];
366
    this.dsp_signed = state[12];
367

368
    // this.dac_buffers = state[13];
369
    //state[14]
370

371
    this.dma_sample_count = state[15];
372
    this.dma_bytes_count = state[16];
373
    this.dma_bytes_left = state[17];
374
    this.dma_bytes_block = state[18];
375
    this.dma_irq = state[19];
376
    this.dma_channel = state[20];
377
    this.dma_channel_8bit = state[21];
378
    this.dma_channel_16bit = state[22];
379
    this.dma_autoinit = state[23];
380
    this.dma_buffer_uint8 = state[24];
381
    this.dma_waiting_transfer = state[25];
382
    this.dma_paused = state[26];
383
    this.sampling_rate = state[27];
384
    this.bytes_per_sample = state[28];
385

386
    this.e2_value = state[29];
387
    this.e2_count = state[30];
388

389
    this.asp_registers = state[31];
390

391
    // this.mpu_read_buffer = state[32];
392
    this.mpu_read_buffer_last_value = state[33];
393

394
    this.irq = state[34];
395
    this.irq_triggered = state[35];
396
    //state[36];
397

398
    this.dma_buffer = this.dma_buffer_uint8.buffer;
399
    this.dma_buffer_int8 = new Int8Array(this.dma_buffer);
400
    this.dma_buffer_int16 = new Int16Array(this.dma_buffer);
401
    this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer);
402
    this.dma_syncbuffer = new SyncBuffer(this.dma_buffer);
403

404
    if(this.dma_paused)
405
    {
406
        this.bus.send("dac-disable");
407
    }
408
    else
409
    {
410
        this.bus.send("dac-enable");
411
    }
412
};
413

414
//
415
// I/O handlers
416
//
417

418
SB16.prototype.port2x0_read = function()
419
{
420
    dbg_log("220 read: fm music status port (unimplemented)", LOG_SB16);
421
    return 0xFF;
422
};
423

424
SB16.prototype.port2x1_read = function()
425
{
426
    dbg_log("221 read: fm music data port (write only)", LOG_SB16);
427
    return 0xFF;
428
};
429

430
SB16.prototype.port2x2_read = function()
431
{
432
    dbg_log("222 read: advanced fm music status port (unimplemented)", LOG_SB16);
433
    return 0xFF;
434
};
435

436
SB16.prototype.port2x3_read = function()
437
{
438
    dbg_log("223 read: advanced music data port (write only)", LOG_SB16);
439
    return 0xFF;
440
};
441

442
// Mixer Address Port.
443
SB16.prototype.port2x4_read = function()
444
{
445
    dbg_log("224 read: mixer address port", LOG_SB16);
446
    return this.mixer_current_address;
447
};
448

449
// Mixer Data Port.
450
SB16.prototype.port2x5_read = function()
451
{
452
    dbg_log("225 read: mixer data port", LOG_SB16);
453
    return this.mixer_read(this.mixer_current_address);
454
};
455

456
SB16.prototype.port2x6_read = function()
457
{
458
    dbg_log("226 read: (write only)", LOG_SB16);
459
    return 0xFF;
460
};
461

462
SB16.prototype.port2x7_read = function()
463
{
464
    dbg_log("227 read: undocumented", LOG_SB16);
465
    return 0xFF;
466
};
467

468
SB16.prototype.port2x8_read = function()
469
{
470
    dbg_log("228 read: fm music status port (unimplemented)", LOG_SB16);
471
    return 0xFF;
472
};
473

474
SB16.prototype.port2x9_read = function()
475
{
476
    dbg_log("229 read: fm music data port (write only)", LOG_SB16);
477
    return 0xFF;
478
};
479

480
// Read Data.
481
// Used to access in-bound DSP data.
482
SB16.prototype.port2xA_read = function()
483
{
484
    dbg_log("22A read: read data", LOG_SB16);
485
    if(this.read_buffer.length)
486
    {
487
        this.read_buffer_lastvalue = this.read_buffer.shift();
488
    }
489
    dbg_log(" <- " + this.read_buffer_lastvalue + " " + h(this.read_buffer_lastvalue) + " '" + String.fromCharCode(this.read_buffer_lastvalue) + "'", LOG_SB16);
490
    return this.read_buffer_lastvalue;
491
};
492

493
SB16.prototype.port2xB_read = function()
494
{
495
    dbg_log("22B read: undocumented", LOG_SB16);
496
    return 0xFF;
497
};
498

499
// Write-Buffer Status.
500
// Indicates whether the DSP is ready to accept commands or data.
501
SB16.prototype.port2xC_read = function()
502
{
503
    dbg_log("22C read: write-buffer status", LOG_SB16);
504
    // Always return ready (bit-7 set to low)
505
    return 0x7F;
506
};
507

508
SB16.prototype.port2xD_read = function()
509
{
510
    dbg_log("22D read: undocumented", LOG_SB16);
511
    return 0xFF;
512
};
513

514
// Read-Buffer Status.
515
// Indicates whether there is any in-bound data available for reading.
516
// Also used to acknowledge DSP 8-bit interrupt.
517
SB16.prototype.port2xE_read = function()
518
{
519
    dbg_log("22E read: read-buffer status / irq 8bit ack.", LOG_SB16);
520
    if(this.irq_triggered[SB_IRQ_8BIT])
521
    {
522
        this.lower_irq(SB_IRQ_8BIT);
523
    }
524
    var ready = this.read_buffer.length && !this.dsp_highspeed;
525
    return (ready << 7) | 0x7F;
526
};
527

528
// DSP 16-bit interrupt acknowledgement.
529
SB16.prototype.port2xF_read = function()
530
{
531
    dbg_log("22F read: irq 16bit ack", LOG_SB16);
532
    this.lower_irq(SB_IRQ_16BIT);
533
    return 0;
534
};
535

536

537
// FM Address Port - primary register.
538
SB16.prototype.port2x0_write = function(value)
539
{
540
    dbg_log("220 write: (unimplemented) fm register 0 address = " + h(value), LOG_SB16);
541
    this.fm_current_address0 = 0;
542
};
543

544
// FM Data Port - primary register.
545
SB16.prototype.port2x1_write = function(value)
546
{
547
    dbg_log("221 write: (unimplemented) fm register 0 data = " + h(value), LOG_SB16);
548
    var handler = FM_HANDLERS[this.fm_current_address0];
549
    if(!handler)
550
    {
551
        handler = this.fm_default_write;
552
    }
553
    handler.call(this, value, 0, this.fm_current_address0);
554
};
555

556
// FM Address Port - secondary register.
557
SB16.prototype.port2x2_write = function(value)
558
{
559
    dbg_log("222 write: (unimplemented) fm register 1 address = " + h(value), LOG_SB16);
560
    this.fm_current_address1 = 0;
561
};
562

563
// FM Data Port - secondary register.
564
SB16.prototype.port2x3_write = function(value)
565
{
566
    dbg_log("223 write: (unimplemented) fm register 1 data =" + h(value), LOG_SB16);
567
    var handler = FM_HANDLERS[this.fm_current_address1];
568
    if(!handler)
569
    {
570
        handler = this.fm_default_write;
571
    }
572
    handler.call(this, value, 1, this.fm_current_address1);
573
};
574

575
// Mixer Address Port.
576
SB16.prototype.port2x4_write = function(value)
577
{
578
    dbg_log("224 write: mixer address = " + h(value), LOG_SB16);
579
    this.mixer_current_address = value;
580
};
581

582
// Mixer Data Port.
583
SB16.prototype.port2x5_write = function(value)
584
{
585
    dbg_log("225 write: mixer data = " + h(value), LOG_SB16);
586
    this.mixer_write(this.mixer_current_address, value);
587
};
588

589
// Reset.
590
// Used to reset the DSP to its default state and to exit highspeed mode.
591
SB16.prototype.port2x6_write = function(yesplease)
592
{
593
    dbg_log("226 write: reset = " + h(yesplease), LOG_SB16);
594

595
    if(this.dsp_highspeed)
596
    {
597
        dbg_log(" -> exit highspeed", LOG_SB16);
598
        this.dsp_highspeed = false;
599
    }
600
    else if(yesplease)
601
    {
602
        dbg_log(" -> reset", LOG_SB16);
603
        this.dsp_reset();
604
    }
605

606
    // Signal completion.
607
    this.read_buffer.clear();
608
    this.read_buffer.push(0xAA);
609
};
610

611
SB16.prototype.port2x7_write = function(value)
612
{
613
    dbg_log("227 write: undocumented", LOG_SB16);
614
};
615

616
SB16.prototype.port2x8_write = function(value)
617
{
618
    dbg_log("228 write: fm music register port (unimplemented)", LOG_SB16);
619
};
620

621
SB16.prototype.port2x9_write = function(value)
622
{
623
    dbg_log("229 write: fm music data port (unimplemented)", LOG_SB16);
624
};
625

626
SB16.prototype.port2xA_write = function(value)
627
{
628
    dbg_log("22A write: dsp read data port (read only)", LOG_SB16);
629
};
630

631
SB16.prototype.port2xB_write = function(value)
632
{
633
    dbg_log("22B write: undocumented", LOG_SB16);
634
};
635

636
// Write Command/Data.
637
// Used to send commands or data to the DSP.
638
SB16.prototype.port2xC_write = function(value)
639
{
640
    dbg_log("22C write: write command/data", LOG_SB16);
641

642
    if(this.command === DSP_NO_COMMAND)
643
    {
644
        // New command.
645
        dbg_log("22C write: command = " + h(value), LOG_SB16);
646
        this.command = value;
647
        this.write_buffer.clear();
648
        this.command_size = DSP_COMMAND_SIZES[value];
649
    }
650
    else
651
    {
652
        // More data for current command.
653
        dbg_log("22C write: data: " + h(value), LOG_SB16);
654
        this.write_buffer.push(value);
655
    }
656

657
    // Perform command when we have all the needed data.
658
    if(this.write_buffer.length >= this.command_size)
659
    {
660
        this.command_do();
661
    }
662
};
663

664
SB16.prototype.port2xD_write = function(value)
665
{
666
    dbg_log("22D write: undocumented", LOG_SB16);
667
};
668

669
SB16.prototype.port2xE_write = function(value)
670
{
671
    dbg_log("22E write: dsp read buffer status (read only)", LOG_SB16);
672
};
673

674
SB16.prototype.port2xF_write = function(value)
675
{
676
    dbg_log("22F write: undocumented", LOG_SB16);
677
};
678

679

680
// MPU UART Mode - Data Port
681
SB16.prototype.port3x0_read = function()
682
{
683
    dbg_log("330 read: mpu data", LOG_SB16);
684

685
    if(this.mpu_read_buffer.length)
686
    {
687
        this.mpu_read_buffer_lastvalue = this.mpu_read_buffer.shift();
688
    }
689
    dbg_log(" <- " + h(this.mpu_read_buffer_lastvalue), LOG_SB16);
690

691
    return this.mpu_read_buffer_lastvalue;
692
};
693
SB16.prototype.port3x0_write = function(value)
694
{
695
    dbg_log("330 write: mpu data (unimplemented) : " + h(value), LOG_SB16);
696
};
697

698
// MPU UART Mode - Status Port
699
SB16.prototype.port3x1_read = function()
700
{
701
    dbg_log("331 read: mpu status", LOG_SB16);
702

703
    var status = 0;
704
    status |= 0x40 * 0; // Output Ready
705
    status |= 0x80 * !this.mpu_read_buffer.length; // Input Ready
706

707
    return status;
708
};
709

710
// MPU UART Mode - Command Port
711
SB16.prototype.port3x1_write = function(value)
712
{
713
    dbg_log("331 write: mpu command: " + h(value), LOG_SB16);
714
    if(value == 0xFF)
715
    {
716
        // Command acknowledge.
717
        this.mpu_read_buffer.clear();
718
        this.mpu_read_buffer.push(0xFE);
719
    }
720
};
721

722
//
723
// DSP command handlers
724
//
725

726
SB16.prototype.command_do = function()
727
{
728
    var handler = DSP_COMMAND_HANDLERS[this.command];
729
    if(!handler)
730
    {
731
        handler = this.dsp_default_handler;
732
    }
733
    handler.call(this);
734

735
    // Reset Inputs.
736
    this.command = DSP_NO_COMMAND;
737
    this.command_size = 0;
738
    this.write_buffer.clear();
739
};
740

741
SB16.prototype.dsp_default_handler = function()
742
{
743
    dbg_log("Unhandled command: " + h(this.command), LOG_SB16);
744
};
745

746
/**
747
 * @param {Array} commands
748
 * @param {number} size
749
 * @param {function()=} handler
750
 */
751
function register_dsp_command(commands, size, handler)
752
{
753
    if(!handler)
754
    {
755
        handler = SB16.prototype.dsp_default_handler;
756
    }
757
    for(var i = 0; i < commands.length; i++)
758
    {
759
        DSP_COMMAND_SIZES[commands[i]] = size;
760
        DSP_COMMAND_HANDLERS[commands[i]] = handler;
761
    }
762
}
763

764
function any_first_digit(base)
765
{
766
    var commands = [];
767
    for(var i = 0; i < 16; i++)
768
    {
769
        commands.push(base + i);
770
    }
771
    return commands;
772
}
773

774
// ASP set register
775
register_dsp_command([0x0E], 2, function()
776
{
777
    this.asp_registers[this.write_buffer.shift()] = this.write_buffer.shift();
778
});
779

780
// ASP get register
781
register_dsp_command([0x0F], 1, function()
782
{
783
    this.read_buffer.clear();
784
    this.read_buffer.push(this.asp_registers[this.write_buffer.shift()]);
785
});
786

787
// 8-bit direct mode single byte digitized sound output.
788
register_dsp_command([0x10], 1, function()
789
{
790
    var value = audio_normalize(this.write_buffer.shift(), 127.5, -1);
791

792
    this.dac_buffers[0].push(value);
793
    this.dac_buffers[1].push(value);
794
    this.bus.send("dac-enable");
795
});
796

797
// 8-bit single-cycle DMA mode digitized sound output.
798
register_dsp_command([0x14, 0x15], 2, function()
799
{
800
    this.dma_irq = SB_IRQ_8BIT;
801
    this.dma_channel = this.dma_channel_8bit;
802
    this.dma_autoinit = false;
803
    this.dsp_signed = false;
804
    this.dsp_16bit = false;
805
    this.dsp_highspeed = false;
806
    this.dma_transfer_size_set();
807
    this.dma_transfer_start();
808
});
809

810
// Creative 8-bit to 2-bit ADPCM single-cycle DMA mode digitized sound output.
811
register_dsp_command([0x16], 2);
812

813
// Creative 8-bit to 2-bit ADPCM single-cycle DMA mode digitzed sound output
814
// with reference byte.
815
register_dsp_command([0x17], 2);
816

817
// 8-bit auto-init DMA mode digitized sound output.
818
register_dsp_command([0x1C], 0, function()
819
{
820
    this.dma_irq = SB_IRQ_8BIT;
821
    this.dma_channel = this.dma_channel_8bit;
822
    this.dma_autoinit = true;
823
    this.dsp_signed = false;
824
    this.dsp_16bit = false;
825
    this.dsp_highspeed = false;
826
    this.dma_transfer_start();
827
});
828

829
// Creative 8-bit to 2-bit ADPCM auto-init DMA mode digitized sound output
830
// with reference byte.
831
register_dsp_command([0x1F], 0);
832

833
// 8-bit direct mode single byte digitized sound input.
834
register_dsp_command([0x20], 0, function()
835
{
836
    // Fake silent input.
837
    this.read_buffer.clear();
838
    this.read_buffer.push(0x7f);
839
});
840

841
// 8-bit single-cycle DMA mode digitized sound input.
842
register_dsp_command([0x24], 2);
843

844
// 8-bit auto-init DMA mode digitized sound input.
845
register_dsp_command([0x2C], 0);
846

847
// Polling mode MIDI input.
848
register_dsp_command([0x30], 0);
849

850
// Interrupt mode MIDI input.
851
register_dsp_command([0x31], 0);
852

853
// UART polling mode MIDI I/O.
854
register_dsp_command([0x34], 0);
855

856
// UART interrupt mode MIDI I/O.
857
register_dsp_command([0x35], 0);
858

859
// UART polling mode MIDI I/O with time stamping.
860
register_dsp_command([0x36], 0);
861

862
// UART interrupt mode MIDI I/O with time stamping.
863
register_dsp_command([0x37], 0);
864

865
// MIDI output.
866
register_dsp_command([0x38], 0);
867

868
// Set digitized sound transfer Time Constant.
869
register_dsp_command([0x40], 1, function()
870
{
871
    // Note: bTimeConstant = 256 * time constant
872
    this.sampling_rate_change(
873
        1000000 / (256 - this.write_buffer.shift()) / this.get_channel_count()
874
    );
875
});
876

877
// Set digitized sound output sampling rate.
878
// Set digitized sound input sampling rate.
879
register_dsp_command([0x41, 0x42], 2, function()
880
{
881
    this.sampling_rate_change((this.write_buffer.shift() << 8) | this.write_buffer.shift());
882
});
883

884
// Set DSP block transfer size.
885
register_dsp_command([0x48], 2, function()
886
{
887
    // TODO: should be in bytes, but if this is only used
888
    // for 8 bit transfers, then this number is the same
889
    // as number of samples?
890
    // Wrong: e.g. stereo requires two bytes per sample.
891
    this.dma_transfer_size_set();
892
});
893

894
// Creative 8-bit to 4-bit ADPCM single-cycle DMA mode digitized sound output.
895
register_dsp_command([0x74], 2);
896

897
// Creative 8-bit to 4-bit ADPCM single-cycle DMA mode digitized sound output
898
// with referene byte.
899
register_dsp_command([0x75], 2);
900

901
// Creative 8-bit to 3-bit ADPCM single-cycle DMA mode digitized sound output.
902
register_dsp_command([0x76], 2);
903

904
// Creative 8-bit to 3-bit ADPCM single-cycle DMA mode digitized sound output
905
// with referene byte.
906
register_dsp_command([0x77], 2);
907

908
// Creative 8-bit to 4-bit ADPCM auto-init DMA mode digitized sound output
909
// with reference byte.
910
register_dsp_command([0x7D], 0);
911

912
// Creative 8-bit to 3-bit ADPCM auto-init DMA mode digitized sound output
913
// with reference byte.
914
register_dsp_command([0x7F], 0);
915

916
// Pause DAC for a duration.
917
register_dsp_command([0x80], 2);
918

919
// 8-bit high-speed auto-init DMA mode digitized sound output.
920
register_dsp_command([0x90], 0, function()
921
{
922
    this.dma_irq = SB_IRQ_8BIT;
923
    this.dma_channel = this.dma_channel_8bit;
924
    this.dma_autoinit = true;
925
    this.dsp_signed = false;
926
    this.dsp_highspeed = true;
927
    this.dsp_16bit = false;
928
    this.dma_transfer_start();
929
});
930

931
// 8-bit high-speed single-cycle DMA mode digitized sound input.
932
register_dsp_command([0x91], 0);
933

934
// 8-bit high-speed auto-init DMA mode digitized sound input.
935
register_dsp_command([0x98], 0);
936

937
// 8-bit high-speed single-cycle DMA mode digitized sound input.
938
register_dsp_command([0x99], 0);
939

940
// Set input mode to mono.
941
register_dsp_command([0xA0], 0);
942

943
// Set input mode to stereo.
944
register_dsp_command([0xA8], 0);
945

946
// Program 16-bit DMA mode digitized sound I/O.
947
register_dsp_command(any_first_digit(0xB0), 3, function()
948
{
949
    if(this.command & (1 << 3))
950
    {
951
        // Analogue to digital not implemented.
952
        this.dsp_default_handler();
953
        return;
954
    }
955
    var mode = this.write_buffer.shift();
956
    this.dma_irq = SB_IRQ_16BIT;
957
    this.dma_channel = this.dma_channel_16bit;
958
    this.dma_autoinit = !!(this.command & (1 << 2));
959
    this.dsp_signed = !!(mode & (1 << 4));
960
    this.dsp_stereo = !!(mode & (1 << 5));
961
    this.dsp_16bit = true;
962
    this.dma_transfer_size_set();
963
    this.dma_transfer_start();
964
});
965

966
// Program 8-bit DMA mode digitized sound I/O.
967
register_dsp_command(any_first_digit(0xC0), 3, function()
968
{
969
    if(this.command & (1 << 3))
970
    {
971
        // Analogue to digital not implemented.
972
        this.dsp_default_handler();
973
        return;
974
    }
975
    var mode = this.write_buffer.shift();
976
    this.dma_irq = SB_IRQ_8BIT;
977
    this.dma_channel = this.dma_channel_8bit;
978
    this.dma_autoinit = !!(this.command & (1 << 2));
979
    this.dsp_signed = !!(mode & (1 << 4));
980
    this.dsp_stereo = !!(mode & (1 << 5));
981
    this.dsp_16bit = false;
982
    this.dma_transfer_size_set();
983
    this.dma_transfer_start();
984
});
985

986
// Pause 8-bit DMA mode digitized sound I/O.
987
register_dsp_command([0xD0], 0, function()
988
{
989
    this.dma_paused = true;
990
    this.bus.send("dac-disable");
991
});
992

993
// Turn on speaker.
994
// Documented to have no effect on SB16.
995
register_dsp_command([0xD1], 0, function()
996
{
997
    this.dummy_speaker_enabled = true;
998
});
999

1000
// Turn off speaker.
1001
// Documented to have no effect on SB16.
1002
register_dsp_command([0xD3], 0, function()
1003
{
1004
    this.dummy_speaker_enabled = false;
1005
});
1006

1007
// Continue 8-bit DMA mode digitized sound I/O.
1008
register_dsp_command([0xD4], 0, function()
1009
{
1010
    this.dma_paused = false;
1011
    this.bus.send("dac-enable");
1012
});
1013

1014
// Pause 16-bit DMA mode digitized sound I/O.
1015
register_dsp_command([0xD5], 0, function()
1016
{
1017
    this.dma_paused = true;
1018
    this.bus.send("dac-disable");
1019
});
1020

1021
// Continue 16-bit DMA mode digitized sound I/O.
1022
register_dsp_command([0xD6], 0, function()
1023
{
1024
    this.dma_paused = false;
1025
    this.bus.send("dac-enable");
1026
});
1027

1028
// Get speaker status.
1029
register_dsp_command([0xD8], 0, function()
1030
{
1031
    this.read_buffer.clear();
1032
    this.read_buffer.push(this.dummy_speaker_enabled * 0xFF);
1033
});
1034

1035
// Exit 16-bit auto-init DMA mode digitized sound I/O.
1036
// Exit 8-bit auto-init mode digitized sound I/O.
1037
register_dsp_command([0xD9, 0xDA], 0, function()
1038
{
1039
    this.dma_autoinit = false;
1040
});
1041

1042
// DSP identification
1043
register_dsp_command([0xE0], 1, function()
1044
{
1045
    this.read_buffer.clear();
1046
    this.read_buffer.push(~this.write_buffer.shift());
1047
});
1048

1049
// Get DSP version number.
1050
register_dsp_command([0xE1], 0, function()
1051
{
1052
    this.read_buffer.clear();
1053
    this.read_buffer.push(4);
1054
    this.read_buffer.push(5);
1055
});
1056

1057
// DMA identification.
1058
register_dsp_command([0xE2], 1);
1059

1060
// Get DSP copyright.
1061
register_dsp_command([0xE3], 0, function()
1062
{
1063
    this.read_buffer.clear();
1064
    for(var i = 0; i < DSP_COPYRIGHT.length; i++)
1065
    {
1066
        this.read_buffer.push(DSP_COPYRIGHT.charCodeAt(i));
1067
    }
1068
    // Null terminator.
1069
    this.read_buffer.push(0);
1070
});
1071

1072
// Write test register.
1073
register_dsp_command([0xE4], 1, function()
1074
{
1075
    this.test_register = this.write_buffer.shift();
1076
});
1077

1078
// Read test register.
1079
register_dsp_command([0xE8], 0, function()
1080
{
1081
    this.read_buffer.clear();
1082
    this.read_buffer.push(this.test_register);
1083
});
1084

1085
// Trigger IRQ
1086
register_dsp_command([0xF2, 0xF3], 0, function()
1087
{
1088
    this.raise_irq();
1089
});
1090

1091
// ASP - unknown function
1092
var SB_F9 = new Uint8Array(256);
1093
SB_F9[0x0E] = 0xFF;
1094
SB_F9[0x0F] = 0x07;
1095
SB_F9[0x37] = 0x38;
1096
register_dsp_command([0xF9], 1, function()
1097
{
1098
    var input = this.write_buffer.shift();
1099
    dbg_log("dsp 0xf9: unknown function. input: " + input, LOG_SB16);
1100

1101
    this.read_buffer.clear();
1102
    this.read_buffer.push(SB_F9[input]);
1103
});
1104

1105
//
1106
// Mixer Handlers (CT1745)
1107
//
1108

1109
SB16.prototype.mixer_read = function(address)
1110
{
1111
    var handler = MIXER_READ_HANDLERS[address];
1112
    var data;
1113
    if(handler)
1114
    {
1115
        data = handler.call(this);
1116
    }
1117
    else
1118
    {
1119
        data = this.mixer_registers[address];
1120
        dbg_log("unhandled mixer register read. addr:" + h(address) + " data:" + h(data), LOG_SB16);
1121
    }
1122
    return data;
1123
};
1124

1125
SB16.prototype.mixer_write = function(address, data)
1126
{
1127
    var handler = MIXER_WRITE_HANDLERS[address];
1128
    if(handler)
1129
    {
1130
        handler.call(this, data);
1131
    }
1132
    else
1133
    {
1134
        dbg_log("unhandled mixer register write. addr:" + h(address) + " data:" + h(data), LOG_SB16);
1135
    }
1136
};
1137

1138
SB16.prototype.mixer_default_read = function()
1139
{
1140
    dbg_log("mixer register read. addr:" + h(this.mixer_current_address), LOG_SB16);
1141
    return this.mixer_registers[this.mixer_current_address];
1142
};
1143

1144
SB16.prototype.mixer_default_write = function(data)
1145
{
1146
    dbg_log("mixer register write. addr:" + h(this.mixer_current_address) + " data:" + h(data), LOG_SB16);
1147
    this.mixer_registers[this.mixer_current_address] = data;
1148
};
1149

1150
SB16.prototype.mixer_reset = function()
1151
{
1152
    // Values intentionally in decimal.
1153
    // Default values available at
1154
    // https://pdos.csail.mit.edu/6.828/2011/readings/hardware/SoundBlaster.pdf
1155
    this.mixer_registers[0x04] = 12 << 4 | 12;
1156
    this.mixer_registers[0x22] = 12 << 4 | 12;
1157
    this.mixer_registers[0x26] = 12 << 4 | 12;
1158
    this.mixer_registers[0x28] = 0;
1159
    this.mixer_registers[0x2E] = 0;
1160
    this.mixer_registers[0x0A] = 0;
1161
    this.mixer_registers[0x30] = 24 << 3;
1162
    this.mixer_registers[0x31] = 24 << 3;
1163
    this.mixer_registers[0x32] = 24 << 3;
1164
    this.mixer_registers[0x33] = 24 << 3;
1165
    this.mixer_registers[0x34] = 24 << 3;
1166
    this.mixer_registers[0x35] = 24 << 3;
1167
    this.mixer_registers[0x36] = 0;
1168
    this.mixer_registers[0x37] = 0;
1169
    this.mixer_registers[0x38] = 0;
1170
    this.mixer_registers[0x39] = 0;
1171
    this.mixer_registers[0x3B] = 0;
1172
    this.mixer_registers[0x3C] = 0x1F;
1173
    this.mixer_registers[0x3D] = 0x15;
1174
    this.mixer_registers[0x3E] = 0x0B;
1175
    this.mixer_registers[0x3F] = 0;
1176
    this.mixer_registers[0x40] = 0;
1177
    this.mixer_registers[0x41] = 0;
1178
    this.mixer_registers[0x42] = 0;
1179
    this.mixer_registers[0x43] = 0;
1180
    this.mixer_registers[0x44] = 8 << 4;
1181
    this.mixer_registers[0x45] = 8 << 4;
1182
    this.mixer_registers[0x46] = 8 << 4;
1183
    this.mixer_registers[0x47] = 8 << 4;
1184

1185
    this.mixer_full_update();
1186
};
1187

1188
SB16.prototype.mixer_full_update = function()
1189
{
1190
    // Start at 1. Don't re-reset.
1191
    for(var i = 1; i < this.mixer_registers.length; i++)
1192
    {
1193
        if(MIXER_REGISTER_IS_LEGACY[i])
1194
        {
1195
            // Legacy registers are actually mapped to other register locations. Update
1196
            // using the new registers rather than the legacy registers.
1197
            continue;
1198
        }
1199
        this.mixer_write(i, this.mixer_registers[i]);
1200
    }
1201
};
1202

1203
/**
1204
 * @param{number} address
1205
 * @param{function():number=} handler
1206
 */
1207
function register_mixer_read(address, handler)
1208
{
1209
    if(!handler)
1210
    {
1211
        handler = SB16.prototype.mixer_default_read;
1212
    }
1213
    MIXER_READ_HANDLERS[address] = handler;
1214
}
1215

1216
/**
1217
 * @param{number} address
1218
 * @param{function(number)=} handler
1219
 */
1220
function register_mixer_write(address, handler)
1221
{
1222
    if(!handler)
1223
    {
1224
        handler = SB16.prototype.mixer_default_write;
1225
    }
1226
    MIXER_WRITE_HANDLERS[address] = handler;
1227
}
1228

1229
// Legacy registers map each nibble to the last 4 bits of the new registers
1230
function register_mixer_legacy(address_old, address_new_left, address_new_right)
1231
{
1232
    MIXER_REGISTER_IS_LEGACY[address_old] = 1;
1233

1234
    /** @this {SB16} */
1235
    MIXER_READ_HANDLERS[address_old] = function()
1236
    {
1237
        var left = this.mixer_registers[address_new_left] & 0xF0;
1238
        var right = this.mixer_registers[address_new_right] >>> 4;
1239
        return left | right;
1240
    };
1241

1242
    /** @this {SB16} */
1243
    MIXER_WRITE_HANDLERS[address_old] = function(data)
1244
    {
1245
        this.mixer_registers[address_old] = data;
1246
        var prev_left = this.mixer_registers[address_new_left];
1247
        var prev_right = this.mixer_registers[address_new_right];
1248
        var left = (data & 0xF0) | (prev_left & 0x0F);
1249
        var right = (data << 4 & 0xF0) | (prev_right & 0x0F);
1250

1251
        this.mixer_write(address_new_left, left);
1252
        this.mixer_write(address_new_right, right);
1253
    };
1254
}
1255

1256
/**
1257
 * @param {number} address
1258
 * @param {number} mixer_source
1259
 * @param {number} channel
1260
 */
1261
function register_mixer_volume(address, mixer_source, channel)
1262
{
1263
    MIXER_READ_HANDLERS[address] = SB16.prototype.mixer_default_read;
1264

1265
    /** @this {SB16} */
1266
    MIXER_WRITE_HANDLERS[address] = function(data)
1267
    {
1268
        this.mixer_registers[address] = data;
1269
        this.bus.send("mixer-volume",
1270
        [
1271
            mixer_source,
1272
            channel,
1273
            (data >>> 2) - 62
1274
        ]);
1275
    };
1276
}
1277

1278
// Reset.
1279
register_mixer_read(0x00, function()
1280
{
1281
    this.mixer_reset();
1282
    return 0;
1283
});
1284
register_mixer_write(0x00);
1285

1286
// Legacy Voice Volume Left/Right.
1287
register_mixer_legacy(0x04, 0x32, 0x33);
1288

1289
// Legacy Mic Volume. TODO.
1290
//register_mixer_read(0x0A);
1291
//register_mixer_write(0x0A, function(data)
1292
//{
1293
//    this.mixer_registers[0x0A] = data;
1294
//    var prev = this.mixer_registers[0x3A];
1295
//    this.mixer_write(0x3A, data << 5 | (prev & 0x0F));
1296
//});
1297

1298
// Legacy Master Volume Left/Right.
1299
register_mixer_legacy(0x22, 0x30, 0x31);
1300
// Legacy Midi Volume Left/Right.
1301
register_mixer_legacy(0x26, 0x34, 0x35);
1302
// Legacy CD Volume Left/Right.
1303
register_mixer_legacy(0x28, 0x36, 0x37);
1304
// Legacy Line Volume Left/Right.
1305
register_mixer_legacy(0x2E, 0x38, 0x39);
1306

1307
// Master Volume Left.
1308
register_mixer_volume(0x30, MIXER_SRC_MASTER, MIXER_CHANNEL_LEFT);
1309
// Master Volume Right.
1310
register_mixer_volume(0x31, MIXER_SRC_MASTER, MIXER_CHANNEL_RIGHT);
1311
// Voice Volume Left.
1312
register_mixer_volume(0x32, MIXER_SRC_DAC, MIXER_CHANNEL_LEFT);
1313
// Voice Volume Right.
1314
register_mixer_volume(0x33, MIXER_SRC_DAC, MIXER_CHANNEL_RIGHT);
1315
// MIDI Volume Left. TODO.
1316
//register_mixer_volume(0x34, MIXER_SRC_SYNTH, MIXER_CHANNEL_LEFT);
1317
// MIDI Volume Right. TODO.
1318
//register_mixer_volume(0x35, MIXER_SRC_SYNTH, MIXER_CHANNEL_RIGHT);
1319
// CD Volume Left. TODO.
1320
//register_mixer_volume(0x36, MIXER_SRC_CD, MIXER_CHANNEL_LEFT);
1321
// CD Volume Right. TODO.
1322
//register_mixer_volume(0x37, MIXER_SRC_CD, MIXER_CHANNEL_RIGHT);
1323
// Line Volume Left. TODO.
1324
//register_mixer_volume(0x38, MIXER_SRC_LINE, MIXER_CHANNEL_LEFT);
1325
// Line Volume Right. TODO.
1326
//register_mixer_volume(0x39, MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT);
1327
// Mic Volume. TODO.
1328
//register_mixer_volume(0x3A, MIXER_SRC_MIC, MIXER_CHANNEL_BOTH);
1329

1330
// PC Speaker Volume.
1331
register_mixer_read(0x3B);
1332
register_mixer_write(0x3B, function(data)
1333
{
1334
    this.mixer_registers[0x3B] = data;
1335
    this.bus.send("mixer-volume", [MIXER_SRC_PCSPEAKER, MIXER_CHANNEL_BOTH, (data >>> 6) * 6 - 18]);
1336
});
1337

1338
// Output Mixer Switches. TODO.
1339
//register_mixer_read(0x3C);
1340
//register_mixer_write(0x3C, function(data)
1341
//{
1342
//    this.mixer_registers[0x3C] = data;
1343
//
1344
//    if(data & 0x01) this.bus.send("mixer-connect", [MIXER_SRC_MIC, MIXER_CHANNEL_BOTH]);
1345
//    else this.bus.send("mixer-disconnect", [MIXER_SRC_MIC, MIXER_CHANNEL_BOTH]);
1346
//
1347
//    if(data & 0x02) this.bus.send("mixer-connect", [MIXER_SRC_CD, MIXER_CHANNEL_RIGHT]);
1348
//    else this.bus.send("mixer-disconnect", [MIXER_SRC_CD, MIXER_CHANNEL_RIGHT]);
1349
//
1350
//    if(data & 0x04) this.bus.send("mixer-connect", [MIXER_SRC_CD, MIXER_CHANNEL_LEFT]);
1351
//    else this.bus.send("mixer-disconnect", [MIXER_SRC_CD, MIXER_CHANNEL_LEFT]);
1352
//
1353
//    if(data & 0x08) this.bus.send("mixer-connect", [MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT]);
1354
//    else this.bus.send("mixer-disconnect", [MIXER_SRC_LINE, MIXER_CHANNEL_RIGHT]);
1355
//
1356
//    if(data & 0x10) this.bus.send("mixer-connect", [MIXER_SRC_LINE, MIXER_CHANNEL_LEFT]);
1357
//    else this.bus.send("mixer-disconnect", [MIXER_SRC_LINE, MIXER_CHANNEL_LEFT]);
1358
//});
1359

1360
// Input Mixer Left Switches. TODO.
1361
//register_mixer_read(0x3D);
1362
//register_mixer_write(0x3D);
1363

1364
// Input Mixer Right Switches. TODO.
1365
//register_mixer_read(0x3E);
1366
//register_mixer_write(0x3E);
1367

1368
// Input Gain Left. TODO.
1369
//register_mixer_read(0x3F);
1370
//register_mixer_write(0x3F);
1371

1372
// Input Gain Right. TODO.
1373
//register_mixer_read(0x40);
1374
//register_mixer_write(0x40);
1375

1376
// Output Gain Left.
1377
register_mixer_read(0x41);
1378
register_mixer_write(0x41, function(data)
1379
{
1380
    this.mixer_registers[0x41] = data;
1381
    this.bus.send("mixer-gain-left", (data >>> 6) * 6);
1382
});
1383

1384
// Output Gain Right.
1385
register_mixer_read(0x42);
1386
register_mixer_write(0x42, function(data)
1387
{
1388
    this.mixer_registers[0x42] = data;
1389
    this.bus.send("mixer-gain-right", (data >>> 6) * 6);
1390
});
1391

1392
// Mic AGC. TODO.
1393
//register_mixer_read(0x43);
1394
//register_mixer_write(0x43);
1395

1396
// Treble Left.
1397
register_mixer_read(0x44);
1398
register_mixer_write(0x44, function(data)
1399
{
1400
    this.mixer_registers[0x44] = data;
1401
    data >>>= 3;
1402
    this.bus.send("mixer-treble-left", data - (data < 16 ? 14 : 16));
1403
});
1404

1405
// Treble Right.
1406
register_mixer_read(0x45);
1407
register_mixer_write(0x45, function(data)
1408
{
1409
    this.mixer_registers[0x45] = data;
1410
    data >>>= 3;
1411
    this.bus.send("mixer-treble-right", data - (data < 16 ? 14 : 16));
1412
});
1413

1414
// Bass Left.
1415
register_mixer_read(0x46);
1416
register_mixer_write(0x46, function(data)
1417
{
1418
    this.mixer_registers[0x46] = data;
1419
    data >>>= 3;
1420
    this.bus.send("mixer-bass-right", data - (data < 16 ? 14 : 16));
1421
});
1422

1423
// Bass Right.
1424
register_mixer_read(0x47);
1425
register_mixer_write(0x47, function(data)
1426
{
1427
    this.mixer_registers[0x47] = data;
1428
    data >>>= 3;
1429
    this.bus.send("mixer-bass-right", data - (data < 16 ? 14 : 16));
1430
});
1431

1432
// IRQ Select.
1433
register_mixer_read(0x80, function()
1434
{
1435
    switch(this.irq)
1436
    {
1437
        case SB_IRQ2: return 0x1;
1438
        case SB_IRQ5: return 0x2;
1439
        case SB_IRQ7: return 0x4;
1440
        case SB_IRQ10: return 0x8;
1441
        default: return 0x0;
1442
    }
1443
});
1444
register_mixer_write(0x80, function(bits)
1445
{
1446
    if(bits & 0x1) this.irq = SB_IRQ2;
1447
    if(bits & 0x2) this.irq = SB_IRQ5;
1448
    if(bits & 0x4) this.irq = SB_IRQ7;
1449
    if(bits & 0x8) this.irq = SB_IRQ10;
1450
});
1451

1452
// DMA Select.
1453
register_mixer_read(0x81, function()
1454
{
1455
    var ret = 0;
1456
    switch(this.dma_channel_8bit)
1457
    {
1458
        case SB_DMA0: ret |= 0x1; break;
1459
        case SB_DMA1: ret |= 0x2; break;
1460
        // Channel 2 is hardwired to floppy disk.
1461
        case SB_DMA3: ret |= 0x8; break;
1462
    }
1463
    switch(this.dma_channel_16bit)
1464
    {
1465
        // Channel 4 cannot be used.
1466
        case SB_DMA5: ret |= 0x20; break;
1467
        case SB_DMA6: ret |= 0x40; break;
1468
        case SB_DMA7: ret |= 0x80; break;
1469
    }
1470
    return ret;
1471
});
1472
register_mixer_write(0x81, function(bits)
1473
{
1474
    if(bits & 0x1) this.dma_channel_8bit = SB_DMA0;
1475
    if(bits & 0x2) this.dma_channel_8bit = SB_DMA1;
1476
    if(bits & 0x8) this.dma_channel_8bit = SB_DMA3;
1477
    if(bits & 0x20) this.dma_channel_16bit = SB_DMA5;
1478
    if(bits & 0x40) this.dma_channel_16bit = SB_DMA6;
1479
    if(bits & 0x80) this.dma_channel_16bit = SB_DMA7;
1480
});
1481

1482
// IRQ Status.
1483
register_mixer_read(0x82, function()
1484
{
1485
    var ret = 0x20;
1486
    for(var i = 0; i < 16; i++)
1487
    {
1488
        ret |= i * this.irq_triggered[i];
1489
    }
1490
    return ret;
1491
});
1492

1493
//
1494
// FM Handlers
1495
//
1496

1497
SB16.prototype.fm_default_write = function(data, register, address)
1498
{
1499
    dbg_log("unhandled fm register write. addr:" + register + "|" + h(address) + " data:" + h(data), LOG_SB16);
1500
    // No need to save into a dummy register as the registers are write-only.
1501
};
1502

1503
/**
1504
 * @param{Array} addresses
1505
 * @param{function(number, number, number)=} handler
1506
 */
1507
function register_fm_write(addresses, handler)
1508
{
1509
    if(!handler)
1510
    {
1511
        handler = SB16.prototype.fm_default_write;
1512
    }
1513
    for(var i = 0; i < addresses.length; i++)
1514
    {
1515
        FM_HANDLERS[addresses[i]] = handler;
1516
    }
1517
}
1518

1519
function between(start, end)
1520
{
1521
    var a = [];
1522
    for(var i = start; i <= end; i++)
1523
    {
1524
        a.push(i);
1525
    }
1526
    return a;
1527
}
1528

1529
/** @const */ var SB_FM_OPERATORS_BY_OFFSET = new Uint8Array(32);
1530
SB_FM_OPERATORS_BY_OFFSET[0x00] = 0;
1531
SB_FM_OPERATORS_BY_OFFSET[0x01] = 1;
1532
SB_FM_OPERATORS_BY_OFFSET[0x02] = 2;
1533
SB_FM_OPERATORS_BY_OFFSET[0x03] = 3;
1534
SB_FM_OPERATORS_BY_OFFSET[0x04] = 4;
1535
SB_FM_OPERATORS_BY_OFFSET[0x05] = 5;
1536
SB_FM_OPERATORS_BY_OFFSET[0x08] = 6;
1537
SB_FM_OPERATORS_BY_OFFSET[0x09] = 7;
1538
SB_FM_OPERATORS_BY_OFFSET[0x0A] = 8;
1539
SB_FM_OPERATORS_BY_OFFSET[0x0B] = 9;
1540
SB_FM_OPERATORS_BY_OFFSET[0x0C] = 10;
1541
SB_FM_OPERATORS_BY_OFFSET[0x0D] = 11;
1542
SB_FM_OPERATORS_BY_OFFSET[0x10] = 12;
1543
SB_FM_OPERATORS_BY_OFFSET[0x11] = 13;
1544
SB_FM_OPERATORS_BY_OFFSET[0x12] = 14;
1545
SB_FM_OPERATORS_BY_OFFSET[0x13] = 15;
1546
SB_FM_OPERATORS_BY_OFFSET[0x14] = 16;
1547
SB_FM_OPERATORS_BY_OFFSET[0x15] = 17;
1548

1549
function get_fm_operator(register, offset)
1550
{
1551
    return register * 18 + SB_FM_OPERATORS_BY_OFFSET[offset];
1552
}
1553

1554
register_fm_write([0x01], function(bits, register, address)
1555
{
1556
    this.fm_waveform_select_enable[register] = bits & 0x20 > 0;
1557
    this.fm_update_waveforms();
1558
});
1559

1560
// Timer 1 Count.
1561
register_fm_write([0x02]);
1562

1563
// Timer 2 Count.
1564
register_fm_write([0x03]);
1565

1566
register_fm_write([0x04], function(bits, register, address)
1567
{
1568
    switch(register)
1569
    {
1570
        case 0:
1571
            // if(bits & 0x80)
1572
            // {
1573
            //     // IQR Reset
1574
            // }
1575
            // else
1576
            // {
1577
            //     // Timer masks and on/off
1578
            // }
1579
            break;
1580
        case 1:
1581
            // Four-operator enable
1582
            break;
1583
    }
1584
});
1585

1586
register_fm_write([0x05], function(bits, register, address)
1587
{
1588
    if(register === 0)
1589
    {
1590
        // No registers documented here.
1591
        this.fm_default_write(bits, register, address);
1592
        return;
1593
    }
1594
    // OPL3 Mode Enable
1595
});
1596

1597
register_fm_write([0x08], function(bits, register, address)
1598
{
1599
    // Composite sine wave on/off
1600
    // Note select (keyboard split selection method)
1601
});
1602

1603
register_fm_write(between(0x20, 0x35), function(bits, register, address)
1604
{
1605
    var operator = get_fm_operator(register, address - 0x20);
1606
    // Tremolo
1607
    // Vibrato
1608
    // Sustain
1609
    // KSR Envelope Scaling
1610
    // Frequency Multiplication Factor
1611
});
1612

1613
register_fm_write(between(0x40, 0x55), function(bits, register, address)
1614
{
1615
    var operator = get_fm_operator(register, address - 0x40);
1616
    // Key Scale Level
1617
    // Output Level
1618
});
1619

1620
register_fm_write(between(0x60, 0x75), function(bits, register, address)
1621
{
1622
    var operator = get_fm_operator(register, address - 0x60);
1623
    // Attack Rate
1624
    // Decay Rate
1625
});
1626

1627
register_fm_write(between(0x80, 0x95), function(bits, register, address)
1628
{
1629
    var operator = get_fm_operator(register, address - 0x80);
1630
    // Sustain Level
1631
    // Release Rate
1632
});
1633

1634
register_fm_write(between(0xA0, 0xA8), function(bits, register, address)
1635
{
1636
    var channel = address - 0xA0;
1637
    // Frequency Number (Lower 8 bits)
1638
});
1639

1640
register_fm_write(between(0xB0, 0xB8), function(bits, register, address)
1641
{
1642
    // Key-On
1643
    // Block Number
1644
    // Frequency Number (Higher 2 bits)
1645
});
1646

1647
register_fm_write([0xBD], function(bits, register, address)
1648
{
1649
    // Tremelo Depth
1650
    // Vibrato Depth
1651
    // Percussion Mode
1652
    // Bass Drum Key-On
1653
    // Snare Drum Key-On
1654
    // Tom-Tom Key-On
1655
    // Cymbal Key-On
1656
    // Hi-Hat Key-On
1657
});
1658

1659
register_fm_write(between(0xC0, 0xC8), function(bits, register, address)
1660
{
1661
    // Right Speaker Enable
1662
    // Left Speaker Enable
1663
    // Feedback Modulation Factor
1664
    // Synthesis Type
1665
});
1666

1667
register_fm_write(between(0xE0, 0xF5), function(bits, register, address)
1668
{
1669
    var operator = get_fm_operator(register, address - 0xE0);
1670
    // Waveform Select
1671
});
1672

1673
//
1674
// FM behaviours
1675
//
1676

1677
SB16.prototype.fm_update_waveforms = function()
1678
{
1679
    // To be implemented.
1680
};
1681

1682
//
1683
// General behaviours
1684
//
1685

1686
SB16.prototype.sampling_rate_change = function(rate)
1687
{
1688
    this.sampling_rate = rate;
1689
    this.bus.send("dac-tell-sampling-rate", rate);
1690
};
1691

1692
SB16.prototype.get_channel_count = function()
1693
{
1694
    return this.dsp_stereo ? 2 : 1;
1695
};
1696

1697
SB16.prototype.dma_transfer_size_set = function()
1698
{
1699
    this.dma_sample_count = 1 + (this.write_buffer.shift() << 0) + (this.write_buffer.shift() << 8);
1700
};
1701

1702
SB16.prototype.dma_transfer_start = function()
1703
{
1704
    dbg_log("begin dma transfer", LOG_SB16);
1705

1706
    // (1) Setup appropriate settings.
1707

1708
    this.bytes_per_sample = 1;
1709
    if(this.dsp_16bit) this.bytes_per_sample *= 2;
1710

1711
    // Don't count stereo interleaved bits apparently.
1712
    // Disabling this line is needed for sounds to work correctly,
1713
    // especially double buffering autoinit mode.
1714
    // Learnt the hard way.
1715
    // if(this.dsp_stereo) this.bytes_per_sample *= 2;
1716

1717
    this.dma_bytes_count = this.dma_sample_count * this.bytes_per_sample;
1718
    this.dma_bytes_block = SB_DMA_BLOCK_SAMPLES * this.bytes_per_sample;
1719

1720
    // Ensure block size is small enough but not too small, and is divisible by 4
1721
    var max_bytes_block = Math.max(this.dma_bytes_count >> 2 & ~0x3, 32);
1722
    this.dma_bytes_block = Math.min(max_bytes_block, this.dma_bytes_block);
1723

1724
    // (2) Wait until channel is unmasked (if not already)
1725
    this.dma_waiting_transfer = true;
1726
    if(!this.dma.channel_mask[this.dma_channel])
1727
    {
1728
        this.dma_on_unmask(this.dma_channel);
1729
    }
1730
};
1731

1732
SB16.prototype.dma_on_unmask = function(channel)
1733
{
1734
    if(channel !== this.dma_channel || !this.dma_waiting_transfer)
1735
    {
1736
        return;
1737
    }
1738

1739
    // (3) Configure amount of bytes left to transfer and tell speaker adapter
1740
    // to start requesting transfers
1741
    this.dma_waiting_transfer = false;
1742
    this.dma_bytes_left = this.dma_bytes_count;
1743
    this.dma_paused = false;
1744
    this.bus.send("dac-enable");
1745
};
1746

1747
SB16.prototype.dma_transfer_next = function()
1748
{
1749
    dbg_log("dma transfering next block", LOG_SB16);
1750

1751
    var size = Math.min(this.dma_bytes_left, this.dma_bytes_block);
1752
    var samples = Math.floor(size / this.bytes_per_sample);
1753

1754
    this.dma.do_write(this.dma_syncbuffer, 0, size, this.dma_channel, (error) =>
1755
    {
1756
        dbg_log("dma block transfer " + (error ? "unsuccessful" : "successful"), LOG_SB16);
1757
        if(error) return;
1758

1759
        this.dma_to_dac(samples);
1760
        this.dma_bytes_left -= size;
1761

1762
        if(!this.dma_bytes_left)
1763
        {
1764
            // Completed requested transfer of given size.
1765
            this.raise_irq(this.dma_irq);
1766

1767
            if(this.dma_autoinit)
1768
            {
1769
                // Restart the transfer.
1770
                this.dma_bytes_left = this.dma_bytes_count;
1771
            }
1772
        }
1773
    });
1774
};
1775

1776
SB16.prototype.dma_to_dac = function(sample_count)
1777
{
1778
    var amplitude = this.dsp_16bit ? 32767.5 : 127.5;
1779
    var offset = this.dsp_signed ? 0 : -1;
1780
    var repeats = this.dsp_stereo ? 1 : 2;
1781

1782
    var buffer;
1783
    if(this.dsp_16bit)
1784
    {
1785
        buffer = this.dsp_signed ? this.dma_buffer_int16 : this.dma_buffer_uint16;
1786
    }
1787
    else
1788
    {
1789
        buffer = this.dsp_signed ? this.dma_buffer_int8 : this.dma_buffer_uint8;
1790
    }
1791

1792
    var channel = 0;
1793
    for(var i = 0; i < sample_count; i++)
1794
    {
1795
        var sample = audio_normalize(buffer[i], amplitude, offset);
1796
        for(var j = 0; j < repeats; j++)
1797
        {
1798
            this.dac_buffers[channel].push(sample);
1799
            channel ^= 1;
1800
        }
1801
    }
1802

1803
    this.dac_send();
1804
};
1805

1806
SB16.prototype.dac_handle_request = function()
1807
{
1808
    if(!this.dma_bytes_left || this.dma_paused)
1809
    {
1810
        // No more data to transfer or is paused. Send whatever is in the buffers.
1811
        this.dac_send();
1812
    }
1813
    else
1814
    {
1815
        this.dma_transfer_next();
1816
    }
1817
};
1818

1819
SB16.prototype.dac_send = function()
1820
{
1821
    if(!this.dac_buffers[0].length)
1822
    {
1823
        return;
1824
    }
1825

1826
    var out0 = this.dac_buffers[0].shift_block(this.dac_buffers[0].length);
1827
    var out1 = this.dac_buffers[1].shift_block(this.dac_buffers[1].length);
1828
    this.bus.send("dac-send-data", [out0, out1], [out0.buffer, out1.buffer]);
1829
};
1830

1831
SB16.prototype.raise_irq = function(type)
1832
{
1833
    dbg_log("raise irq", LOG_SB16);
1834
    this.irq_triggered[type] = 1;
1835
    this.cpu.device_raise_irq(this.irq);
1836
};
1837

1838
SB16.prototype.lower_irq = function(type)
1839
{
1840
    dbg_log("lower irq", LOG_SB16);
1841
    this.irq_triggered[type] = 0;
1842
    this.cpu.device_lower_irq(this.irq);
1843
};
1844

1845
//
1846
// Helpers
1847
//
1848

1849
function audio_normalize(value, amplitude, offset)
1850
{
1851
    return audio_clip(value / amplitude + offset, -1, 1);
1852
}
1853

1854
function audio_clip(value, low, high)
1855
{
1856
    return (value < low) * low + (value > high) * high + (low <= value && value <= high) * value;
1857
}
1858

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.