Skip to content

Commit a584316

Browse files
committed
OPL4 WIP
1 parent bd2cf29 commit a584316

File tree

5 files changed

+120
-76
lines changed

5 files changed

+120
-76
lines changed

src/main/msx/audio/AudioSignal.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// Copyright 2015 by Paulo Augusto Peccin. See license.txt distributed with this file.
22

3-
wmsx.AudioSignal = function (name, source, volume, sampleRate, clock) {
3+
wmsx.AudioSignal = function (name, source, volume, sampleRate, stereo, clock) {
44
"use strict";
55

66
var self = this;
77

88
function init() {
9+
generateNextSample = stereo ? generateNextSampleStereo : generateNextSampleMono;
10+
generateNextSampleMute = stereo ? generateNextSampleStereoMute : generateNextSampleMonoMute;
911
var multi = Math.floor(wmsx.Machine.BASE_CPU_CLOCK / sampleRate);
1012
var sampleFunc = getAudioSampleFunction(multi);
1113
if (clock) {
@@ -115,8 +117,12 @@ wmsx.AudioSignal = function (name, source, volume, sampleRate, clock) {
115117

116118
function updateBufferSize() {
117119
var size = (monitorBufferSize * WMSX.AUDIO_SIGNAL_BUFFER_RATIO + samplesPerFrame * WMSX.AUDIO_SIGNAL_ADD_FRAMES) | 0;
118-
samples.length = size;
119-
if (size > maxSamples) wmsx.Util.arrayFill(samples, 0, maxSamples, size);
120+
samples0.length = size;
121+
if (size > maxSamples) wmsx.Util.arrayFill(samples0, 0, maxSamples, size);
122+
if (stereo) {
123+
samples1.length = size;
124+
if (size > maxSamples) wmsx.Util.arrayFill(samples1, 0, maxSamples, size);
125+
}
120126
maxSamples = size;
121127
retrieveResult.bufferSize = maxSamples;
122128
maxAvailSamples = maxSamples - 2;
@@ -162,19 +168,31 @@ wmsx.AudioSignal = function (name, source, volume, sampleRate, clock) {
162168
source.audioClockPulse();
163169
}
164170

165-
function generateNextSample() {
166-
samples[nextSampleToGenerate] = source.nextSample() * volume;
171+
function generateNextSampleMono() {
172+
samples0[nextSampleToGenerate] = source.nextSample() * volume;
173+
if (++nextSampleToGenerate >= maxSamples) nextSampleToGenerate = 0; // Circular Buffer
174+
}
175+
function generateNextSampleStereo() {
176+
var sourceSamples = source.nextSample();
177+
samples0[nextSampleToGenerate] = sourceSamples[0] * volume;
178+
samples1[nextSampleToGenerate] = sourceSamples[1] * volume;
167179
if (++nextSampleToGenerate >= maxSamples) nextSampleToGenerate = 0; // Circular Buffer
168180
}
181+
var generateNextSample = generateNextSampleMono;
169182

170-
function generateNextSampleMute() {
171-
samples[nextSampleToGenerate] = 0;
183+
function generateNextSampleMonoMute() {
184+
samples0[nextSampleToGenerate] = 0;
185+
if (++nextSampleToGenerate >= maxSamples) nextSampleToGenerate = 0; // Circular Buffer
186+
}
187+
function generateNextSampleStereoMute() {
188+
samples0[nextSampleToGenerate] = samples1[nextSampleToGenerate] = 0;
172189
if (++nextSampleToGenerate >= maxSamples) nextSampleToGenerate = 0; // Circular Buffer
173190
}
191+
var generateNextSampleMute = generateNextSampleMonoMute;
174192

175193
function generateMissingSamples(quant, mute) {
176-
if (mute) for (var j = quant; j > 0; j = j - 1) generateNextSampleMute()
177-
else for (var i = quant; i > 0; i = i - 1) generateNextSample()
194+
if (mute) for (var j = quant; j > 0; j = j - 1) generateNextSampleMute();
195+
else for (var i = quant; i > 0; i = i - 1) generateNextSample();
178196
availSamples -= quant;
179197
}
180198

@@ -194,12 +212,15 @@ wmsx.AudioSignal = function (name, source, volume, sampleRate, clock) {
194212

195213
var maxSamples = 0;
196214
var availSamples = 0, maxAvailSamples = 0;
197-
var samples = wmsx.Util.arrayFill(new Array(maxSamples), 0);
215+
var samples0 = wmsx.Util.arrayFill(new Array(maxSamples), 0);
216+
var samples1 = wmsx.Util.arrayFill(new Array(maxSamples), 0);
198217

199218
var monitorBufferSize = 0;
200219

201220
var retrieveResult = {
202-
buffer: samples,
221+
stereo: !!stereo,
222+
buffer0: samples0,
223+
buffer1: samples1,
203224
bufferSize: maxSamples,
204225
start: 0
205226
};

src/main/msx/audio/OPL4Audio.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ wmsx.OPL4Audio = function(pName, cart) {
7070

7171
function connectAudio() {
7272
if (audioSocket) {
73-
if (!audioSignal) audioSignal = new wmsx.AudioSignal(name, self, VOLUME, SAMPLE_RATE, CLOCK);
73+
if (!audioSignal) audioSignal = new wmsx.AudioSignal(name, self, VOLUME, SAMPLE_RATE, true, CLOCK);
7474
audioSocket.connectAudioSignal(audioSignal);
7575
audioConnected = true;
7676
}

src/main/msx/audio/OPL4AudioWave.js

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ wmsx.OPL4AudioWave = function(opl4) {
1212
linearTable = tabs.getLinearTable12Bits();
1313
expTable = tabs.getExpTable();
1414
vibValues = tabs.getVIBValues();
15-
kslValues = tabs.getKSLValues();
1615
rateAttackDurTable = tabs.getRateAttackDurations();
1716
rateDecayDurTable = tabs.getRateDecayDurations();
1817
envAttackCurve = tabs.getEnvAttackCurve();
18+
panpotValues = tabs.getPanPotValues();
1919
}
2020

2121
this.connect = function(machine) {
@@ -68,10 +68,10 @@ wmsx.OPL4AudioWave = function(opl4) {
6868

6969
// Dynamic values
7070

71-
wmsx.Util.arrayFill(volumeAtt, 0x7f << 4);
7271
wmsx.Util.arrayFill(amAtt, 0);
7372
wmsx.Util.arrayFill(envAtt, 0x100 << 4);
74-
wmsx.Util.arrayFill(totalAtt, 0x100 << 4);
73+
wmsx.Util.arrayFill(totalAttL, 0x100 << 4);
74+
wmsx.Util.arrayFill(totalAttR, 0x100 << 4);
7575
wmsx.Util.arrayFill(envStep, IDLE);
7676
wmsx.Util.arrayFill(envStepLevelDur, 0);
7777
wmsx.Util.arrayFill(envStepLevelIncClock, 0);
@@ -122,7 +122,7 @@ wmsx.OPL4AudioWave = function(opl4) {
122122

123123
this.nextSample = function() {
124124
var phase, newPhase, delta;
125-
var sample = 0;
125+
var sample = 0, sampleL = 0, sampleR = 0;
126126

127127
for (var cha = 23; cha >= 0; --cha) {
128128
if (envStep[cha] === IDLE) continue;
@@ -133,17 +133,22 @@ wmsx.OPL4AudioWave = function(opl4) {
133133

134134
delta = (newPhase >> 10) - (phase >> 10);
135135

136-
if (delta > 0)
137-
sample += expTable[advanceSample(cha, delta) + totalAtt[cha]];
138-
else
139-
sample += expTable[sampleValue[cha] + totalAtt[cha]];
140-
141-
// if (delta > 0) sample += advanceSample(cha, delta); else sample += sampleValue[cha];
136+
if (delta > 0) {
137+
sample = advanceSample(cha, delta);
138+
sampleL += expTable[sample + totalAttL[cha]];
139+
sampleR += expTable[sample + totalAttR[cha]];
140+
} else {
141+
sampleL += expTable[sampleValue[cha] + totalAttL[cha]];
142+
sampleR += expTable[sampleValue[cha] + totalAttR[cha]];
143+
}
142144

143-
// if (sample > (24 * 4096) || sample < (24 * -4096)) console.log("Wave overflow: " + sample);
145+
// if (delta > 0) sampleL += advanceSample(cha, delta); else sampleL += sampleValue[cha];
146+
// if (sampleL > (24 * 4096) || sampleL < (24 * -4096)) console.log("Wave overflow: " + sampleL);
144147
}
145148

146-
return sample;
149+
sampleResult[0] = sampleL;
150+
sampleResult[1] = sampleR;
151+
return sampleResult;
147152
};
148153

149154
function readWaveHeader(cha) {
@@ -215,7 +220,7 @@ wmsx.OPL4AudioWave = function(opl4) {
215220
cha = reg - 0x50;
216221
if (mod & 0xfe) {
217222
volume[cha] = val >> 1; // TOTAL LEVEL
218-
updateVolumeAttenuation(cha);
223+
updateTotalAttenuation(cha);
219224
}
220225
break;
221226
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: case 0x70: case 0x71: case 0x72: case 0x73:
@@ -224,6 +229,11 @@ wmsx.OPL4AudioWave = function(opl4) {
224229
if (mod & 0x80) setKeyOn(cha, val >> 7); // KEY ON
225230
if (mod & 0x40)
226231
if (val & 0x40) setEnvStep(cha, DAMP_END); // DAMP
232+
if (mod & 0x0f) {
233+
panpotL[cha] = panpotValues[0][val & 0x0f]; // PANPOT
234+
panpotR[cha] = panpotValues[1][val & 0x0f];
235+
updateTotalAttenuation(cha);
236+
}
227237
break;
228238
case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa0: case 0xa1: case 0xa2: case 0xa3:
229239
case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
@@ -477,20 +487,13 @@ wmsx.OPL4AudioWave = function(opl4) {
477487
}
478488

479489
function updateEnvAttenuation(cha) {
480-
envAtt[cha] = (envStep[cha] === ATTACK ? envAttackCurve[envLevel[cha]] : envLevel[cha]) << 4;
481-
updateTotalAttenuation(cha);
482-
}
483-
484-
function updateVolumeAttenuation(cha) {
485-
volumeAtt[cha] = volume[cha] << 4;
490+
envAtt[cha] = envStep[cha] === ATTACK ? envAttackCurve[envLevel[cha]] : envLevel[cha];
486491
updateTotalAttenuation(cha);
487492
}
488493

489494
function updateTotalAttenuation(cha) {
490-
totalAtt[cha] = amAtt[cha] + envAtt[cha] + volumeAtt[cha];
491-
492-
// 0..208 + 0..1792 + 0..2048 + 0..2016
493-
// max: 256 + 2048 + 4096 + 4096 = 10496 = 0x2900
495+
totalAttL[cha] = amAtt[cha] + (envAtt[cha] << 4) + (volume[cha] << 4) + (panpotL[cha] << 7);
496+
totalAttR[cha] = amAtt[cha] + (envAtt[cha] << 4) + (volume[cha] << 4) + (panpotR[cha] << 7);
494497
}
495498

496499

@@ -526,15 +529,17 @@ wmsx.OPL4AudioWave = function(opl4) {
526529
var rc = new Array(24);
527530
var rr = new Array(24);
528531

529-
var am = new Array(24);
530-
var vib = new Array(24);
531-
var volume = new Array(24);
532+
var am = new Array(24);
533+
var vib = new Array(24);
534+
var volume = new Array(24);
535+
var panpotL = new Array(24);
536+
var panpotR = new Array(24);
532537

533538
// Dynamic values per Channel. May change as time passes without being set by software
534539
var amAtt = new Array(24);
535540
var envAtt = new Array(24);
536-
var volumeAtt = new Array(24);
537-
var totalAtt = new Array(24);
541+
var totalAttL = new Array(24);
542+
var totalAttR = new Array(24);
538543

539544
var envStep = new Array(24);
540545
var envStepLevelDur = new Array(24);
@@ -554,7 +559,8 @@ wmsx.OPL4AudioWave = function(opl4) {
554559

555560
// Pre calculated tables, factors, values
556561

557-
var linearTable, expTable, vibValues, kslValues, rateAttackDurTable, rateDecayDurTable, envAttackCurve;
562+
var linearTable, expTable, vibValues, rateAttackDurTable, rateDecayDurTable, envAttackCurve, panpotValues;
563+
var sampleResult = [ 0, 0 ];
558564

559565

560566
// Savestate -------------------------------------------
@@ -580,7 +586,8 @@ wmsx.OPL4AudioWave = function(opl4) {
580586

581587
amt: wmsx.Util.storeInt16BitArrayToStringBase64(amAtt),
582588
evt: wmsx.Util.storeInt16BitArrayToStringBase64(envAtt),
583-
tot: wmsx.Util.storeInt16BitArrayToStringBase64(totalAtt),
589+
totL: wmsx.Util.storeInt16BitArrayToStringBase64(totalAttL),
590+
totR: wmsx.Util.storeInt16BitArrayToStringBase64(totalAttR),
584591

585592
evs: wmsx.Util.storeInt8BitArrayToStringBase64(envStep),
586593
evd: wmsx.Util.storeInt32BitArrayToStringBase64(envStepLevelDur),
@@ -619,7 +626,8 @@ wmsx.OPL4AudioWave = function(opl4) {
619626

620627
amAtt = wmsx.Util.restoreStringBase64ToInt16BitArray(s.amt, amAtt);
621628
envAtt = wmsx.Util.restoreStringBase64ToInt16BitArray(s.evt, envAtt);
622-
totalAtt = wmsx.Util.restoreStringBase64ToInt16BitArray(s.tot, totalAtt);
629+
totalAttL = wmsx.Util.restoreStringBase64ToInt16BitArray(s.totL, totalAttL);
630+
totalAttR = wmsx.Util.restoreStringBase64ToInt16BitArray(s.totR, totalAttR);
623631

624632
envStep = wmsx.Util.restoreStringBase64ToInt8BitArray(s.evs, envStep);
625633
envStepLevelDur = wmsx.Util.restoreStringBase64ToInt32BitArray(s.evd);
@@ -656,8 +664,8 @@ wmsx.OPL4AudioWave = function(opl4) {
656664

657665
this.envAtt = envAtt;
658666
this.amAtt = amAtt;
659-
this.volumeAtt = volumeAtt;
660-
this.totalAtt = totalAtt;
667+
this.totalAttL = totalAttL;
668+
this.totalAttR = totalAttR;
661669

662670
this.envStep = envStep;
663671
this.envStepLevelDur = envStepLevelDur;

src/main/msx/audio/OPL4WaveTables.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ wmsx.OPL4WaveTables = function() {
3838
return this.VIB_VALUES;
3939
};
4040

41-
this.getKSLValues = function() {
42-
return this.KSL_VALUES;
43-
};
44-
4541
this.getRateAttackDurations = function() {
4642
var tab = new Array(76);
4743
for (var i = 0; i < 64; ++i) {
@@ -68,6 +64,10 @@ wmsx.OPL4WaveTables = function() {
6864
return tab;
6965
};
7066

67+
this.getPanPotValues = function() {
68+
return this.PANPOT_VALUES;
69+
};
70+
7171
this.VIB_VALUES = [
7272
[ 0, 0, 0, 0, 0, 0, 0, 0 ], // According to fNum >> 6 (one line for each value)
7373
[ 0, 0, 1, 0, 0, 0, -1, 0 ], // Half these values must be added to fNum BEFORE multi
@@ -117,4 +117,11 @@ wmsx.OPL4WaveTables = function() {
117117
5.44, 5.44, 5.44, 5.44
118118
];
119119

120+
this.PANPOT_VALUES = [
121+
// -3 .. -18 dB. Min = -96 dB
122+
[ 0, 1, 2, 3, 4, 5, 6, 32, 32, 0, 0, 0, 0, 0, 0, 0 ], // L
123+
[ 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 6, 5, 4, 3, 2, 1 ] // R
124+
]
125+
126+
120127
};

0 commit comments

Comments
 (0)