yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dsp.cc
Go to the documentation of this file.
1#include "app/emu/audio/dsp.h"
2
3#include <cmath>
4#include <cstring>
5
6namespace yaze {
7namespace emu {
8
9static const int rateValues[32] = {0, 2048, 1536, 1280, 1024, 768, 640, 512,
10 384, 320, 256, 192, 160, 128, 96, 80,
11 64, 48, 40, 32, 24, 20, 16, 12,
12 10, 8, 6, 5, 4, 3, 2, 1};
13
14static const int rateOffsets[32] = {0, 0, 1040, 536, 0, 1040, 536, 0, 1040,
15 536, 0, 1040, 536, 0, 1040, 536, 0, 1040,
16 536, 0, 1040, 536, 0, 1040, 536, 0, 1040,
17 536, 0, 1040, 536, 0};
18
19static const int gaussValues[512] = {
20 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
21 0x000, 0x000, 0x000, 0x000, 0x000, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
22 0x001, 0x001, 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002,
23 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004,
24 0x005, 0x005, 0x005, 0x005, 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007,
25 0x008, 0x008, 0x008, 0x009, 0x009, 0x009, 0x00a, 0x00a, 0x00a, 0x00b, 0x00b,
26 0x00b, 0x00c, 0x00c, 0x00d, 0x00d, 0x00e, 0x00e, 0x00f, 0x00f, 0x00f, 0x010,
27 0x010, 0x011, 0x011, 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
28 0x017, 0x017, 0x018, 0x018, 0x019, 0x01a, 0x01b, 0x01b, 0x01c, 0x01d, 0x01d,
29 0x01e, 0x01f, 0x020, 0x020, 0x021, 0x022, 0x023, 0x024, 0x024, 0x025, 0x026,
30 0x027, 0x028, 0x029, 0x02a, 0x02b, 0x02c, 0x02d, 0x02e, 0x02f, 0x030, 0x031,
31 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x03a, 0x03b, 0x03c, 0x03d,
32 0x03e, 0x040, 0x041, 0x042, 0x043, 0x045, 0x046, 0x047, 0x049, 0x04a, 0x04c,
33 0x04d, 0x04e, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, 0x05a, 0x05c,
34 0x05e, 0x05f, 0x061, 0x063, 0x064, 0x066, 0x068, 0x06a, 0x06b, 0x06d, 0x06f,
35 0x071, 0x073, 0x075, 0x076, 0x078, 0x07a, 0x07c, 0x07e, 0x080, 0x082, 0x084,
36 0x086, 0x089, 0x08b, 0x08d, 0x08f, 0x091, 0x093, 0x096, 0x098, 0x09a, 0x09c,
37 0x09f, 0x0a1, 0x0a3, 0x0a6, 0x0a8, 0x0ab, 0x0ad, 0x0af, 0x0b2, 0x0b4, 0x0b7,
38 0x0ba, 0x0bc, 0x0bf, 0x0c1, 0x0c4, 0x0c7, 0x0c9, 0x0cc, 0x0cf, 0x0d2, 0x0d4,
39 0x0d7, 0x0da, 0x0dd, 0x0e0, 0x0e3, 0x0e6, 0x0e9, 0x0ec, 0x0ef, 0x0f2, 0x0f5,
40 0x0f8, 0x0fb, 0x0fe, 0x101, 0x104, 0x107, 0x10b, 0x10e, 0x111, 0x114, 0x118,
41 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, 0x130, 0x133, 0x137, 0x13a, 0x13e,
42 0x141, 0x145, 0x148, 0x14c, 0x150, 0x153, 0x157, 0x15b, 0x15f, 0x162, 0x166,
43 0x16a, 0x16e, 0x172, 0x176, 0x17a, 0x17d, 0x181, 0x185, 0x189, 0x18d, 0x191,
44 0x195, 0x19a, 0x19e, 0x1a2, 0x1a6, 0x1aa, 0x1ae, 0x1b2, 0x1b7, 0x1bb, 0x1bf,
45 0x1c3, 0x1c8, 0x1cc, 0x1d0, 0x1d5, 0x1d9, 0x1dd, 0x1e2, 0x1e6, 0x1eb, 0x1ef,
46 0x1f3, 0x1f8, 0x1fc, 0x201, 0x205, 0x20a, 0x20f, 0x213, 0x218, 0x21c, 0x221,
47 0x226, 0x22a, 0x22f, 0x233, 0x238, 0x23d, 0x241, 0x246, 0x24b, 0x250, 0x254,
48 0x259, 0x25e, 0x263, 0x267, 0x26c, 0x271, 0x276, 0x27b, 0x280, 0x284, 0x289,
49 0x28e, 0x293, 0x298, 0x29d, 0x2a2, 0x2a6, 0x2ab, 0x2b0, 0x2b5, 0x2ba, 0x2bf,
50 0x2c4, 0x2c9, 0x2ce, 0x2d3, 0x2d8, 0x2dc, 0x2e1, 0x2e6, 0x2eb, 0x2f0, 0x2f5,
51 0x2fa, 0x2ff, 0x304, 0x309, 0x30e, 0x313, 0x318, 0x31d, 0x322, 0x326, 0x32b,
52 0x330, 0x335, 0x33a, 0x33f, 0x344, 0x349, 0x34e, 0x353, 0x357, 0x35c, 0x361,
53 0x366, 0x36b, 0x370, 0x374, 0x379, 0x37e, 0x383, 0x388, 0x38c, 0x391, 0x396,
54 0x39b, 0x39f, 0x3a4, 0x3a9, 0x3ad, 0x3b2, 0x3b7, 0x3bb, 0x3c0, 0x3c5, 0x3c9,
55 0x3ce, 0x3d2, 0x3d7, 0x3dc, 0x3e0, 0x3e5, 0x3e9, 0x3ed, 0x3f2, 0x3f6, 0x3fb,
56 0x3ff, 0x403, 0x408, 0x40c, 0x410, 0x415, 0x419, 0x41d, 0x421, 0x425, 0x42a,
57 0x42e, 0x432, 0x436, 0x43a, 0x43e, 0x442, 0x446, 0x44a, 0x44e, 0x452, 0x455,
58 0x459, 0x45d, 0x461, 0x465, 0x468, 0x46c, 0x470, 0x473, 0x477, 0x47a, 0x47e,
59 0x481, 0x485, 0x488, 0x48c, 0x48f, 0x492, 0x496, 0x499, 0x49c, 0x49f, 0x4a2,
60 0x4a6, 0x4a9, 0x4ac, 0x4af, 0x4b2, 0x4b5, 0x4b7, 0x4ba, 0x4bd, 0x4c0, 0x4c3,
61 0x4c5, 0x4c8, 0x4cb, 0x4cd, 0x4d0, 0x4d2, 0x4d5, 0x4d7, 0x4d9, 0x4dc, 0x4de,
62 0x4e0, 0x4e3, 0x4e5, 0x4e7, 0x4e9, 0x4eb, 0x4ed, 0x4ef, 0x4f1, 0x4f3, 0x4f5,
63 0x4f6, 0x4f8, 0x4fa, 0x4fb, 0x4fd, 0x4ff, 0x500, 0x502, 0x503, 0x504, 0x506,
64 0x507, 0x508, 0x50a, 0x50b, 0x50c, 0x50d, 0x50e, 0x50f, 0x510, 0x511, 0x511,
65 0x512, 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518,
66 0x518, 0x518, 0x518, 0x518, 0x519, 0x519};
67
68void Dsp::Reset() {
69 memset(ram, 0, sizeof(ram));
70 ram[0x7c] = 0xff; // set ENDx
71 for (int i = 0; i < 8; i++) {
72 channel[i].pitch = 0;
73 channel[i].pitchCounter = 0;
74 channel[i].pitchModulation = false;
75 memset(channel[i].decodeBuffer, 0, sizeof(channel[i].decodeBuffer));
76 channel[i].bufferOffset = 0;
77 channel[i].srcn = 0;
78 channel[i].decodeOffset = 0;
79 channel[i].blockOffset = 0;
80 channel[i].brrHeader = 0;
81 channel[i].useNoise = false;
82 channel[i].startDelay = 0;
83 memset(channel[i].adsrRates, 0, sizeof(channel[i].adsrRates));
84 channel[i].adsrState = 0;
85 channel[i].sustainLevel = 0;
87 channel[i].useGain = false;
88 channel[i].gainMode = 0;
89 channel[i].directGain = false;
90 channel[i].gainValue = 0;
91 channel[i].preclampGain = 0;
92 channel[i].gain = 0;
93 channel[i].keyOn = false;
94 channel[i].keyOff = false;
95 channel[i].sampleOut = 0;
96 channel[i].volumeL = 0;
97 channel[i].volumeR = 0;
98 channel[i].echoEnable = false;
99 }
100 counter = 0;
101 dirPage = 0;
102 evenCycle = true;
103 mute = true;
104 reset = true;
105 masterVolumeL = 0;
106 masterVolumeR = 0;
107 sampleOutL = 0;
108 sampleOutR = 0;
109 echoOutL = 0;
110 echoOutR = 0;
111 noiseSample = 0x4000;
112 noiseRate = 0;
113 echoWrites = false;
114 echoVolumeL = 0;
115 echoVolumeR = 0;
116 feedbackVolume = 0;
117 echoBufferAdr = 0;
118 echoDelay = 0;
119 echoLength = 0;
120 echoBufferIndex = 0;
121 firBufferIndex = 0;
122 memset(firValues, 0, sizeof(firValues));
123 memset(firBufferL, 0, sizeof(firBufferL));
124 memset(firBufferR, 0, sizeof(firBufferR));
125 memset(sampleBuffer, 0, sizeof(sampleBuffer));
126 sampleOffset = 0;
128}
129
133
135 // Clear the sample ring buffer and reset position tracking
136 // This ensures a clean start for new playback without full DSP reset
137 memset(sampleBuffer, 0, sizeof(sampleBuffer));
138 sampleOffset = 0;
140}
141
143 // ========================================================================
144 // DSP Mixing Pipeline
145 // The S-DSP generates samples for 8 voices, applies effects, and mixes
146 // them into a final stereo output. This runs at 32000Hz.
147 // ========================================================================
148
149 // 1. Clear mixing accumulators for the new sample period
150 sampleOutL = 0;
151 sampleOutR = 0;
152 echoOutL = 0;
153 echoOutR = 0;
154
155 // 2. Process all 8 voices (generate samples, pitch, envelope)
156 for (int i = 0; i < 8; i++) {
157 CycleChannel(i);
158 }
159
160 // 3. Apply Echo (FIR Filter) and mix into main output
161 HandleEcho(); // also applies master volume
162
163 // 4. Update Noise Generator (LFSR)
164 // Counter runs at 32000Hz, noise rate divisor determines update freq
165 counter = counter == 0 ? 30720 : counter - 1;
166 HandleNoise();
167
168 // 5. Update State Flags
169 evenCycle = !evenCycle; // Used for Key On/Off timing (every other sample)
170
171 // 6. Apply Mute Flag (FLG bit 6)
172 if (mute) {
173 sampleOutL = 0;
174 sampleOutR = 0;
175 }
176
177 // 7. Output Stage
178 // Store final stereo sample in ring buffer for the APU/Emulator to read
179 sampleBuffer[(sampleOffset & 0x7ff) * 2] = sampleOutL;
180 sampleBuffer[(sampleOffset & 0x7ff) * 2 + 1] = sampleOutR;
181 sampleOffset = (sampleOffset + 1) & 0x7ff;
182}
183
184static int clamp16(int val) {
185 return val < -0x8000 ? -0x8000 : (val > 0x7fff ? 0x7fff : val);
186}
187
188static int clip16(int val) {
189 return (int16_t)(val & 0xffff);
190}
191
192bool Dsp::CheckCounter(int rate) {
193 if (rate == 0)
194 return false;
195 return ((counter + rateOffsets[rate]) % rateValues[rate]) == 0;
196}
197
199 // increment fir buffer index
201 firBufferIndex &= 0x7;
202 // get value out of ram
203 uint16_t adr = echoBufferAdr + echoBufferIndex;
204 int16_t ramSample = aram_[adr] | (aram_[(adr + 1) & 0xffff] << 8);
205 firBufferL[firBufferIndex] = ramSample >> 1;
206 ramSample = aram_[(adr + 2) & 0xffff] | (aram_[(adr + 3) & 0xffff] << 8);
207 firBufferR[firBufferIndex] = ramSample >> 1;
208
209 // Calculate FIR-sum (Finite Impulse Response Filter)
210 // 8-tap filter applied to echo buffer history
211 int sumL = 0, sumR = 0;
212 for (int i = 0; i < 8; i++) {
213 sumL += (firBufferL[(firBufferIndex + i + 1) & 0x7] * firValues[i]) >> 6;
214 sumR += (firBufferR[(firBufferIndex + i + 1) & 0x7] * firValues[i]) >> 6;
215 if (i == 6) {
216 // clip to 16-bit before last addition
217 sumL = clip16(sumL);
218 sumR = clip16(sumR);
219 }
220 }
221 sumL = clamp16(sumL) & ~1;
222 sumR = clamp16(sumR) & ~1;
223
224 // Apply master volume and mix echo into main output
225 // sampleOutL/R currently holds the sum of all voices
226 sampleOutL = clamp16(((sampleOutL * masterVolumeL) >> 7) +
227 ((sumL * echoVolumeL) >> 7));
228 sampleOutR = clamp16(((sampleOutR * masterVolumeR) >> 7) +
229 ((sumR * echoVolumeR) >> 7));
230
231 // Calculate echo feedback for next pass
232 int echoL = clamp16(echoOutL + clip16((sumL * feedbackVolume) >> 7)) & ~1;
233 int echoR = clamp16(echoOutR + clip16((sumR * feedbackVolume) >> 7)) & ~1;
234
235 // Write feedback to echo buffer in RAM
236 if (echoWrites) {
237 aram_[adr] = echoL & 0xff;
238 aram_[(adr + 1) & 0xffff] = echoL >> 8;
239 aram_[(adr + 2) & 0xffff] = echoR & 0xff;
240 aram_[(adr + 3) & 0xffff] = echoR >> 8;
241 }
242 // handle indexes
243 if (echoBufferIndex == 0) {
244 echoLength = echoDelay * 4;
245 }
246 echoBufferIndex += 4;
248 echoBufferIndex = 0;
249 }
250}
251
252void Dsp::CycleChannel(int ch) {
253 // handle pitch counter
254 int pitch = channel[ch].pitch;
255 if (ch > 0 && channel[ch].pitchModulation) {
256 pitch += ((channel[ch - 1].sampleOut >> 5) * pitch) >> 10;
257 }
258 // get current brr header and get sample address
260 uint16_t samplePointer = dirPage + 4 * channel[ch].srcn;
261 if (channel[ch].startDelay == 0)
262 samplePointer += 2;
263 uint16_t sampleAdr =
264 aram_[samplePointer] | (aram_[(samplePointer + 1) & 0xffff] << 8);
265 // handle starting of sample
266 if (channel[ch].startDelay > 0) {
267 if (channel[ch].startDelay == 5) {
268 // first keyed on
269 channel[ch].decodeOffset = sampleAdr;
270 channel[ch].blockOffset = 1;
271 channel[ch].bufferOffset = 0;
272 channel[ch].brrHeader = 0;
273 ram[0x7c] &= ~(1 << ch); // clear ENDx
274 }
275 channel[ch].gain = 0;
276 channel[ch].startDelay--;
277 channel[ch].pitchCounter = 0;
278 if (channel[ch].startDelay > 0 && channel[ch].startDelay < 4) {
279 channel[ch].pitchCounter = 0x4000;
280 }
281 pitch = 0;
282 }
283 // get sample
284 int sample = 0;
285 if (channel[ch].useNoise) {
286 sample = clip16(noiseSample * 2);
287 } else {
288 sample = GetSample(ch); // Interpolated sample from BRR buffer
289 }
290
291 // Apply Gain/Envelope (16-bit * 11-bit -> ~27-bit, scaled back to 16-bit)
292 // The & ~1 clears the bottom bit, a quirk of the SNES DSP
293 sample = ((sample * channel[ch].gain) >> 11) & ~1;
294
295 // handle reset and release
296 if (reset || (channel[ch].brrHeader & 0x03) == 1) {
297 channel[ch].adsrState = 3; // go to release
298 channel[ch].gain = 0;
299 }
300 // handle keyon/keyoff
301 if (evenCycle) {
302 if (channel[ch].keyOff) {
303 channel[ch].adsrState = 3; // go to release
304 }
305 if (channel[ch].keyOn) {
306 channel[ch].startDelay = 5;
307 channel[ch].adsrState = 0; // go to attack
308 channel[ch].keyOn = false;
309 }
310 }
311 // handle envelope
312 if (channel[ch].startDelay == 0) {
313 HandleGain(ch);
314 }
315 // decode new brr samples if needed and update offsets
316 if (channel[ch].pitchCounter >= 0x4000) {
317 DecodeBrr(ch);
318 if (channel[ch].blockOffset >= 7) {
319 if (channel[ch].brrHeader & 0x1) {
320 channel[ch].decodeOffset = sampleAdr;
321 ram[0x7c] |= 1 << ch; // set ENDx
322 } else {
323 channel[ch].decodeOffset += 9;
324 }
325 channel[ch].blockOffset = 1;
326 } else {
327 channel[ch].blockOffset += 2;
328 }
329 }
330 // update pitch counter
331 channel[ch].pitchCounter &= 0x3fff;
332 channel[ch].pitchCounter += pitch;
333 if (channel[ch].pitchCounter > 0x7fff)
334 channel[ch].pitchCounter = 0x7fff;
335
336 // set outputs
337 ram[(ch << 4) | 8] = channel[ch].gain >> 4;
338 ram[(ch << 4) | 9] = sample >> 8;
339 channel[ch].sampleOut = sample;
340
341 if (!debug_mute_channels_[ch]) {
342 // Mix into main output accumulator (with clipping)
343 // (sample * volume) >> 7 scales 16-bit * 7-bit to roughly 16-bit
344 sampleOutL = clamp16(sampleOutL + ((sample * channel[ch].volumeL) >> 7));
345 sampleOutR = clamp16(sampleOutR + ((sample * channel[ch].volumeR) >> 7));
346 if (channel[ch].echoEnable) {
347 echoOutL = clamp16(echoOutL + ((sample * channel[ch].volumeL) >> 7));
348 echoOutR = clamp16(echoOutR + ((sample * channel[ch].volumeR) >> 7));
349 }
350 }
351}
352
353void Dsp::HandleGain(int ch) {
354 int newGain = channel[ch].gain;
355 int rate = 0;
356 // handle gain mode
357 if (channel[ch].adsrState == 3) { // release
358 rate = 31;
359 newGain -= 8;
360 } else {
361 if (!channel[ch].useGain) {
362 rate = channel[ch].adsrRates[channel[ch].adsrState];
363 switch (channel[ch].adsrState) {
364 case 0:
365 newGain += rate == 31 ? 1024 : 32;
366 break; // attack
367 case 1:
368 newGain -= ((newGain - 1) >> 8) + 1;
369 break; // decay
370 case 2:
371 newGain -= ((newGain - 1) >> 8) + 1;
372 break; // sustain
373 }
374 } else {
375 if (!channel[ch].directGain) {
376 rate = channel[ch].adsrRates[3];
377 switch (channel[ch].gainMode) {
378 case 0:
379 newGain -= 32;
380 break; // linear decrease
381 case 1:
382 newGain -= ((newGain - 1) >> 8) + 1;
383 break; // exponential decrease
384 case 2:
385 newGain += 32;
386 break; // linear increase
387 case 3:
388 newGain += (channel[ch].preclampGain < 0x600) ? 32 : 8;
389 break; // bent increase
390 }
391 } else { // direct gain
392 rate = 31;
393 newGain = channel[ch].gainValue;
394 }
395 }
396 }
397 // use sustain level according to mode
398 int sustainLevel = channel[ch].useGain ? channel[ch].gainSustainLevel
399 : channel[ch].sustainLevel;
400 if (channel[ch].adsrState == 1 && (newGain >> 8) == sustainLevel) {
401 channel[ch].adsrState = 2; // go to sustain
402 }
403 // store pre-clamped gain (for bent increase)
404 channel[ch].preclampGain = newGain & 0xffff;
405 // clamp gain
406 if (newGain < 0 || newGain > 0x7ff) {
407 newGain = newGain < 0 ? 0 : 0x7ff;
408 if (channel[ch].adsrState == 0) {
409 channel[ch].adsrState = 1; // go to decay
410 }
411 }
412 // store new value
413 if (CheckCounter(rate))
414 channel[ch].gain = newGain;
415}
416
417int16_t Dsp::GetSample(int ch) {
418 // Gaussian interpolation using a 512-entry lookup table
419 int pos = (channel[ch].pitchCounter >> 12) + channel[ch].bufferOffset;
420 int offset = (channel[ch].pitchCounter >> 4) & 0xff;
421 int16_t news = channel[ch].decodeBuffer[(pos + 3) % 12];
422 int16_t olds = channel[ch].decodeBuffer[(pos + 2) % 12];
423 int16_t olders = channel[ch].decodeBuffer[(pos + 1) % 12];
424 int16_t oldests = channel[ch].decodeBuffer[pos % 12];
425 int out = (gaussValues[0xff - offset] * oldests) >> 11;
426 out += (gaussValues[0x1ff - offset] * olders) >> 11;
427 out += (gaussValues[0x100 + offset] * olds) >> 11;
428 out = clip16(out) + ((gaussValues[offset] * news) >> 11);
429 return clamp16(out) & ~1;
430}
431
432void Dsp::DecodeBrr(int ch) {
433 int shift = channel[ch].brrHeader >> 4;
434 int filter = (channel[ch].brrHeader & 0xc) >> 2;
435 int bOff = channel[ch].bufferOffset;
436 int old = channel[ch].decodeBuffer[bOff == 0 ? 11 : bOff - 1] >> 1;
437 int older = channel[ch].decodeBuffer[bOff == 0 ? 10 : bOff - 2] >> 1;
438 uint8_t curByte = 0;
439 for (int i = 0; i < 4; i++) {
440 int s = 0;
441 if (i & 1) {
442 s = curByte & 0xf;
443 } else {
444 curByte = aram_[(channel[ch].decodeOffset + channel[ch].blockOffset +
445 (i >> 1)) &
446 0xffff];
447 s = curByte >> 4;
448 }
449 if (s > 7)
450 s -= 16;
451 if (shift <= 0xc) {
452 s = (s << shift) >> 1;
453 } else {
454 s = (s >> 3) << 12;
455 }
456 switch (filter) {
457 case 1:
458 s += old + (-old >> 4);
459 break;
460 case 2:
461 s += 2 * old + ((3 * -old) >> 5) - older + (older >> 4);
462 break;
463 case 3:
464 s += 2 * old + ((13 * -old) >> 6) - older + ((3 * older) >> 4);
465 break;
466 }
467 channel[ch].decodeBuffer[bOff + i] = clamp16(s) * 2; // cuts off bit 15
468 older = old;
469 old = channel[ch].decodeBuffer[bOff + i] >> 1;
470 }
471 channel[ch].bufferOffset += 4;
472 if (channel[ch].bufferOffset >= 12)
473 channel[ch].bufferOffset = 0;
474}
475
477 if (CheckCounter(noiseRate)) {
478 int bit = (noiseSample & 1) ^ ((noiseSample >> 1) & 1);
479 noiseSample = ((noiseSample >> 1) & 0x3fff) | (bit << 14);
480 }
481}
482
483uint8_t Dsp::Read(uint8_t adr) {
484 return ram[adr];
485}
486
487void Dsp::Write(uint8_t adr, uint8_t val) {
488 int ch = adr >> 4;
489 switch (adr) {
490 case 0x00:
491 case 0x10:
492 case 0x20:
493 case 0x30:
494 case 0x40:
495 case 0x50:
496 case 0x60:
497 case 0x70: {
498 channel[ch].volumeL = val;
499 break;
500 }
501 case 0x01:
502 case 0x11:
503 case 0x21:
504 case 0x31:
505 case 0x41:
506 case 0x51:
507 case 0x61:
508 case 0x71: {
509 channel[ch].volumeR = val;
510 break;
511 }
512 case 0x02:
513 case 0x12:
514 case 0x22:
515 case 0x32:
516 case 0x42:
517 case 0x52:
518 case 0x62:
519 case 0x72: {
520 channel[ch].pitch = (channel[ch].pitch & 0x3f00) | val;
521 break;
522 }
523 case 0x03:
524 case 0x13:
525 case 0x23:
526 case 0x33:
527 case 0x43:
528 case 0x53:
529 case 0x63:
530 case 0x73: {
531 channel[ch].pitch = ((channel[ch].pitch & 0x00ff) | (val << 8)) & 0x3fff;
532 break;
533 }
534 case 0x04:
535 case 0x14:
536 case 0x24:
537 case 0x34:
538 case 0x44:
539 case 0x54:
540 case 0x64:
541 case 0x74: {
542 channel[ch].srcn = val;
543 break;
544 }
545 case 0x05:
546 case 0x15:
547 case 0x25:
548 case 0x35:
549 case 0x45:
550 case 0x55:
551 case 0x65:
552 case 0x75: {
553 channel[ch].adsrRates[0] = (val & 0xf) * 2 + 1;
554 channel[ch].adsrRates[1] = ((val & 0x70) >> 4) * 2 + 16;
555 channel[ch].useGain = (val & 0x80) == 0;
556 break;
557 }
558 case 0x06:
559 case 0x16:
560 case 0x26:
561 case 0x36:
562 case 0x46:
563 case 0x56:
564 case 0x66:
565 case 0x76: {
566 channel[ch].adsrRates[2] = val & 0x1f;
567 channel[ch].sustainLevel = (val & 0xe0) >> 5;
568 break;
569 }
570 case 0x07:
571 case 0x17:
572 case 0x27:
573 case 0x37:
574 case 0x47:
575 case 0x57:
576 case 0x67:
577 case 0x77: {
578 channel[ch].directGain = (val & 0x80) == 0;
579 channel[ch].gainMode = (val & 0x60) >> 5;
580 channel[ch].adsrRates[3] = val & 0x1f;
581 channel[ch].gainValue = (val & 0x7f) * 16;
582 channel[ch].gainSustainLevel = (val & 0xe0) >> 5;
583 break;
584 }
585 case 0x0c: {
586 masterVolumeL = val;
587 break;
588 }
589 case 0x1c: {
590 masterVolumeR = val;
591 break;
592 }
593 case 0x2c: {
594 echoVolumeL = val;
595 break;
596 }
597 case 0x3c: {
598 echoVolumeR = val;
599 break;
600 }
601 case 0x4c: {
602 for (int i = 0; i < 8; i++) {
603 channel[i].keyOn = val & (1 << i);
604 }
605 break;
606 }
607 case 0x5c: {
608 for (int i = 0; i < 8; i++) {
609 channel[i].keyOff = val & (1 << i);
610 }
611 break;
612 }
613 case 0x6c: {
614 reset = val & 0x80;
615 mute = val & 0x40;
616 echoWrites = (val & 0x20) == 0;
617 noiseRate = val & 0x1f;
618 break;
619 }
620 case 0x7c: {
621 val = 0; // any write clears ENDx
622 break;
623 }
624 case 0x0d: {
625 feedbackVolume = val;
626 break;
627 }
628 case 0x2d: {
629 for (int i = 0; i < 8; i++) {
630 channel[i].pitchModulation = val & (1 << i);
631 }
632 break;
633 }
634 case 0x3d: {
635 for (int i = 0; i < 8; i++) {
636 channel[i].useNoise = val & (1 << i);
637 }
638 break;
639 }
640 case 0x4d: {
641 for (int i = 0; i < 8; i++) {
642 channel[i].echoEnable = val & (1 << i);
643 }
644 break;
645 }
646 case 0x5d: {
647 dirPage = val << 8;
648 break;
649 }
650 case 0x6d: {
651 echoBufferAdr = val << 8;
652 break;
653 }
654 case 0x7d: {
655 echoDelay =
656 (val & 0xf) * 512; // 2048-byte steps, stereo sample is 4 bytes
657 break;
658 }
659 case 0x0f:
660 case 0x1f:
661 case 0x2f:
662 case 0x3f:
663 case 0x4f:
664 case 0x5f:
665 case 0x6f:
666 case 0x7f: {
667 firValues[ch] = val;
668 break;
669 }
670 }
671 ram[adr] = val;
672}
673
674// Helper for 4-point cubic interpolation (Catmull-Rom)
675// Provides higher quality resampling compared to linear interpolation.
676inline int16_t InterpolateCubic(int16_t p0, int16_t p1, int16_t p2, int16_t p3,
677 double t) {
678 double t2 = t * t;
679 double t3 = t2 * t;
680
681 double c0 = p1;
682 double c1 = 0.5 * (p2 - p0);
683 double c2 = (p0 - 2.5 * p1 + 2.0 * p2 - 0.5 * p3);
684 double c3 = 0.5 * (-p0 + 3.0 * p1 - 3.0 * p2 + p3);
685
686 double result = c0 + c1 * t + c2 * t2 + c3 * t3;
687
688 // Clamp to 16-bit range
689 return result > 32767.0
690 ? 32767
691 : (result < -32768.0 ? -32768 : static_cast<int16_t>(result));
692}
693
694// Helper for cosine interpolation
695inline int16_t InterpolateCosine(int16_t s0, int16_t s1, double mu) {
696 const double mu2 = (1.0 - cos(mu * 3.14159265358979323846)) / 2.0;
697 return static_cast<int16_t>(s0 * (1.0 - mu2) + s1 * mu2);
698}
699
700// Helper for linear interpolation
701inline int16_t InterpolateLinear(int16_t s0, int16_t s1, double frac) {
702 return static_cast<int16_t>(s0 + frac * (s1 - s0));
703}
704
705// Helper for Hermite interpolation (used by bsnes/Snes9x)
706// Provides smoother interpolation than linear with minimal overhead
707inline int16_t InterpolateHermite(int16_t p0, int16_t p1, int16_t p2,
708 int16_t p3, double t) {
709 const double c0 = p1;
710 const double c1 = (p2 - p0) * 0.5;
711 const double c2 = p0 - 2.5 * p1 + 2.0 * p2 - 0.5 * p3;
712 const double c3 = (p3 - p0) * 0.5 + 1.5 * (p1 - p2);
713
714 const double result = c0 + c1 * t + c2 * t * t + c3 * t * t * t;
715
716 // Clamp to 16-bit range
717 return result > 32767.0
718 ? 32767
719 : (result < -32768.0 ? -32768 : static_cast<int16_t>(result));
720}
721
722void Dsp::GetSamples(int16_t* sample_data, int samples_per_frame,
723 bool pal_timing) {
724 // Resample from native samples-per-frame based on precise SNES timing.
725 // NTSC: 32040 Hz / 60.0988 Hz/frame = ~533.122 samples/frame
726 // PAL: 32040 Hz / 50.007 Hz/frame = ~640.71 samples/frame
727 const double native_per_frame = pal_timing ? (32040.0 / 50.007) : (32040.0 / 60.0988);
728 const double step = native_per_frame / static_cast<double>(samples_per_frame);
729
730 // Start reading one native frame behind the frame boundary
731 double location = static_cast<double>((lastFrameBoundary + 0x800) & 0x7ff);
732 location -= native_per_frame;
733
734 // Ensure location is within valid range
735 while (location < 0)
736 location += 0x800;
737
738 for (int i = 0; i < samples_per_frame; i++) {
739 const int idx = static_cast<int>(location) & 0x7ff;
740 const double frac = location - static_cast<int>(location);
741
742 switch (interpolation_type) {
744 const int next_idx = (idx + 1) & 0x7ff;
745
746 // Linear interpolation for left channel
747 const int16_t s0_l = sampleBuffer[(idx * 2) + 0];
748 const int16_t s1_l = sampleBuffer[(next_idx * 2) + 0];
749 sample_data[(i * 2) + 0] =
750 static_cast<int16_t>(s0_l + frac * (s1_l - s0_l));
751
752 // Linear interpolation for right channel
753 const int16_t s0_r = sampleBuffer[(idx * 2) + 1];
754 const int16_t s1_r = sampleBuffer[(next_idx * 2) + 1];
755 sample_data[(i * 2) + 1] =
756 static_cast<int16_t>(s0_r + frac * (s1_r - s0_r));
757 break;
758 }
760 const int idx0 = (idx - 1 + 0x800) & 0x7ff;
761 const int idx1 = idx & 0x7ff;
762 const int idx2 = (idx + 1) & 0x7ff;
763 const int idx3 = (idx + 2) & 0x7ff;
764 // Left channel
765 const int16_t p0_l = sampleBuffer[(idx0 * 2) + 0];
766 const int16_t p1_l = sampleBuffer[(idx1 * 2) + 0];
767 const int16_t p2_l = sampleBuffer[(idx2 * 2) + 0];
768 const int16_t p3_l = sampleBuffer[(idx3 * 2) + 0];
769 sample_data[(i * 2) + 0] =
770 InterpolateHermite(p0_l, p1_l, p2_l, p3_l, frac);
771 // Right channel
772 const int16_t p0_r = sampleBuffer[(idx0 * 2) + 1];
773 const int16_t p1_r = sampleBuffer[(idx1 * 2) + 1];
774 const int16_t p2_r = sampleBuffer[(idx2 * 2) + 1];
775 const int16_t p3_r = sampleBuffer[(idx3 * 2) + 1];
776 sample_data[(i * 2) + 1] =
777 InterpolateHermite(p0_r, p1_r, p2_r, p3_r, frac);
778 break;
779 }
781 const int offset = static_cast<int>(frac * 256.0) & 0xff;
782 const int idx0 = (idx - 1 + 0x800) & 0x7ff;
783 const int idx1 = idx & 0x7ff;
784 const int idx2 = (idx + 1) & 0x7ff;
785 const int idx3 = (idx + 2) & 0x7ff;
786
787 // Left channel
788 const int16_t p0_l = sampleBuffer[(idx0 * 2) + 0];
789 const int16_t p1_l = sampleBuffer[(idx1 * 2) + 0];
790 const int16_t p2_l = sampleBuffer[(idx2 * 2) + 0];
791 const int16_t p3_l = sampleBuffer[(idx3 * 2) + 0];
792
793 int out_l = (gaussValues[0xff - offset] * p0_l) >> 11;
794 out_l += (gaussValues[0x1ff - offset] * p1_l) >> 11;
795 out_l += (gaussValues[0x100 + offset] * p2_l) >> 11;
796 out_l = clip16(out_l) + ((gaussValues[offset] * p3_l) >> 11);
797 sample_data[(i * 2) + 0] = clamp16(out_l) & ~1;
798
799 // Right channel
800 const int16_t p0_r = sampleBuffer[(idx0 * 2) + 1];
801 const int16_t p1_r = sampleBuffer[(idx1 * 2) + 1];
802 const int16_t p2_r = sampleBuffer[(idx2 * 2) + 1];
803 const int16_t p3_r = sampleBuffer[(idx3 * 2) + 1];
804
805 int out_r = (gaussValues[0xff - offset] * p0_r) >> 11;
806 out_r += (gaussValues[0x1ff - offset] * p1_r) >> 11;
807 out_r += (gaussValues[0x100 + offset] * p2_r) >> 11;
808 out_r = clip16(out_r) + ((gaussValues[offset] * p3_r) >> 11);
809 sample_data[(i * 2) + 1] = clamp16(out_r) & ~1;
810 break;
811 }
813 const int next_idx = (idx + 1) & 0x7ff; // Fixed: use full 2048 buffer
814 const int16_t s0_l = sampleBuffer[(idx * 2) + 0];
815 const int16_t s1_l = sampleBuffer[(next_idx * 2) + 0];
816 sample_data[(i * 2) + 0] = InterpolateCosine(s0_l, s1_l, frac);
817 const int16_t s0_r = sampleBuffer[(idx * 2) + 1];
818 const int16_t s1_r = sampleBuffer[(next_idx * 2) + 1];
819 sample_data[(i * 2) + 1] = InterpolateCosine(s0_r, s1_r, frac);
820 break;
821 }
823 const int idx0 = (idx - 1 + 0x800) & 0x7ff; // Fixed: use full 2048 buffer
824 const int idx1 = idx & 0x7ff;
825 const int idx2 = (idx + 1) & 0x7ff;
826 const int idx3 = (idx + 2) & 0x7ff;
827 // Left channel
828 const int16_t p0_l = sampleBuffer[(idx0 * 2) + 0];
829 const int16_t p1_l = sampleBuffer[(idx1 * 2) + 0];
830 const int16_t p2_l = sampleBuffer[(idx2 * 2) + 0];
831 const int16_t p3_l = sampleBuffer[(idx3 * 2) + 0];
832 sample_data[(i * 2) + 0] =
833 InterpolateCubic(p0_l, p1_l, p2_l, p3_l, frac);
834 // Right channel
835 const int16_t p0_r = sampleBuffer[(idx0 * 2) + 1];
836 const int16_t p1_r = sampleBuffer[(idx1 * 2) + 1];
837 const int16_t p2_r = sampleBuffer[(idx2 * 2) + 1];
838 const int16_t p3_r = sampleBuffer[(idx3 * 2) + 1];
839 sample_data[(i * 2) + 1] =
840 InterpolateCubic(p0_r, p1_r, p2_r, p3_r, frac);
841 break;
842 }
843 }
844 location += step;
845 }
846}
847
848int Dsp::CopyNativeFrame(int16_t* sample_data, bool pal_timing) {
849 if (sample_data == nullptr) {
850 return 0;
851 }
852
853 const int native_per_frame = pal_timing ? 641 : 534;
854 const int total_samples = native_per_frame * 2;
855
856 int start_index =
857 static_cast<int>((lastFrameBoundary + 0x800 - native_per_frame) & 0x7ff);
858
859 for (int i = 0; i < native_per_frame; ++i) {
860 const int idx = (start_index + i) & 0x7ff; // Fixed: use full 2048 buffer
861 sample_data[(i * 2) + 0] = sampleBuffer[(idx * 2) + 0];
862 sample_data[(i * 2) + 1] = sampleBuffer[(idx * 2) + 1];
863 }
864
865 return total_samples / 2; // return frames per channel
866}
867
868void Dsp::SaveState(std::ostream& stream) {
869 stream.write(reinterpret_cast<const char*>(ram), sizeof(ram));
870 auto write_bool = [&](bool value) {
871 uint8_t encoded = value ? 1 : 0;
872 stream.write(reinterpret_cast<const char*>(&encoded), sizeof(encoded));
873 };
874 auto write_channel = [&](const DspChannel& ch) {
875 stream.write(reinterpret_cast<const char*>(&ch.pitch), sizeof(ch.pitch));
876 stream.write(reinterpret_cast<const char*>(&ch.pitchCounter),
877 sizeof(ch.pitchCounter));
878 write_bool(ch.pitchModulation);
879 stream.write(reinterpret_cast<const char*>(ch.decodeBuffer),
880 sizeof(ch.decodeBuffer));
881 stream.write(reinterpret_cast<const char*>(&ch.bufferOffset),
882 sizeof(ch.bufferOffset));
883 stream.write(reinterpret_cast<const char*>(&ch.srcn), sizeof(ch.srcn));
884 stream.write(reinterpret_cast<const char*>(&ch.decodeOffset),
885 sizeof(ch.decodeOffset));
886 stream.write(reinterpret_cast<const char*>(&ch.blockOffset),
887 sizeof(ch.blockOffset));
888 stream.write(reinterpret_cast<const char*>(&ch.brrHeader),
889 sizeof(ch.brrHeader));
890 write_bool(ch.useNoise);
891 stream.write(reinterpret_cast<const char*>(&ch.startDelay),
892 sizeof(ch.startDelay));
893 stream.write(reinterpret_cast<const char*>(ch.adsrRates),
894 sizeof(ch.adsrRates));
895 stream.write(reinterpret_cast<const char*>(&ch.adsrState),
896 sizeof(ch.adsrState));
897 stream.write(reinterpret_cast<const char*>(&ch.sustainLevel),
898 sizeof(ch.sustainLevel));
899 stream.write(reinterpret_cast<const char*>(&ch.gainSustainLevel),
900 sizeof(ch.gainSustainLevel));
901 write_bool(ch.useGain);
902 stream.write(reinterpret_cast<const char*>(&ch.gainMode),
903 sizeof(ch.gainMode));
904 write_bool(ch.directGain);
905 stream.write(reinterpret_cast<const char*>(&ch.gainValue),
906 sizeof(ch.gainValue));
907 stream.write(reinterpret_cast<const char*>(&ch.preclampGain),
908 sizeof(ch.preclampGain));
909 stream.write(reinterpret_cast<const char*>(&ch.gain), sizeof(ch.gain));
910 write_bool(ch.keyOn);
911 write_bool(ch.keyOff);
912 stream.write(reinterpret_cast<const char*>(&ch.sampleOut),
913 sizeof(ch.sampleOut));
914 stream.write(reinterpret_cast<const char*>(&ch.volumeL),
915 sizeof(ch.volumeL));
916 stream.write(reinterpret_cast<const char*>(&ch.volumeR),
917 sizeof(ch.volumeR));
918 write_bool(ch.echoEnable);
919 };
920 for (const auto& ch : channel) {
921 write_channel(ch);
922 }
923
924 stream.write(reinterpret_cast<const char*>(&counter), sizeof(counter));
925 stream.write(reinterpret_cast<const char*>(&dirPage), sizeof(dirPage));
926 stream.write(reinterpret_cast<const char*>(&evenCycle), sizeof(evenCycle));
927 stream.write(reinterpret_cast<const char*>(&mute), sizeof(mute));
928 stream.write(reinterpret_cast<const char*>(&reset), sizeof(reset));
929 stream.write(reinterpret_cast<const char*>(&masterVolumeL), sizeof(masterVolumeL));
930 stream.write(reinterpret_cast<const char*>(&masterVolumeR), sizeof(masterVolumeR));
931
932 stream.write(reinterpret_cast<const char*>(&sampleOutL), sizeof(sampleOutL));
933 stream.write(reinterpret_cast<const char*>(&sampleOutR), sizeof(sampleOutR));
934 stream.write(reinterpret_cast<const char*>(&echoOutL), sizeof(echoOutL));
935 stream.write(reinterpret_cast<const char*>(&echoOutR), sizeof(echoOutR));
936
937 stream.write(reinterpret_cast<const char*>(&noiseSample), sizeof(noiseSample));
938 stream.write(reinterpret_cast<const char*>(&noiseRate), sizeof(noiseRate));
939
940 stream.write(reinterpret_cast<const char*>(&echoWrites), sizeof(echoWrites));
941 stream.write(reinterpret_cast<const char*>(&echoVolumeL), sizeof(echoVolumeL));
942 stream.write(reinterpret_cast<const char*>(&echoVolumeR), sizeof(echoVolumeR));
943 stream.write(reinterpret_cast<const char*>(&feedbackVolume), sizeof(feedbackVolume));
944 stream.write(reinterpret_cast<const char*>(&echoBufferAdr), sizeof(echoBufferAdr));
945 stream.write(reinterpret_cast<const char*>(&echoDelay), sizeof(echoDelay));
946 stream.write(reinterpret_cast<const char*>(&echoLength), sizeof(echoLength));
947 stream.write(reinterpret_cast<const char*>(&echoBufferIndex), sizeof(echoBufferIndex));
948 stream.write(reinterpret_cast<const char*>(&firBufferIndex), sizeof(firBufferIndex));
949
950 stream.write(reinterpret_cast<const char*>(firValues), sizeof(firValues));
951 stream.write(reinterpret_cast<const char*>(firBufferL), sizeof(firBufferL));
952 stream.write(reinterpret_cast<const char*>(firBufferR), sizeof(firBufferR));
953
954 stream.write(reinterpret_cast<const char*>(&lastFrameBoundary), sizeof(lastFrameBoundary));
955}
956
957void Dsp::LoadState(std::istream& stream) {
958 stream.read(reinterpret_cast<char*>(ram), sizeof(ram));
959 auto read_bool = [&](bool* value) {
960 uint8_t encoded = 0;
961 stream.read(reinterpret_cast<char*>(&encoded), sizeof(encoded));
962 *value = encoded != 0;
963 };
964 auto read_channel = [&](DspChannel& ch) {
965 stream.read(reinterpret_cast<char*>(&ch.pitch), sizeof(ch.pitch));
966 stream.read(reinterpret_cast<char*>(&ch.pitchCounter),
967 sizeof(ch.pitchCounter));
968 read_bool(&ch.pitchModulation);
969 stream.read(reinterpret_cast<char*>(ch.decodeBuffer),
970 sizeof(ch.decodeBuffer));
971 stream.read(reinterpret_cast<char*>(&ch.bufferOffset),
972 sizeof(ch.bufferOffset));
973 stream.read(reinterpret_cast<char*>(&ch.srcn), sizeof(ch.srcn));
974 stream.read(reinterpret_cast<char*>(&ch.decodeOffset),
975 sizeof(ch.decodeOffset));
976 stream.read(reinterpret_cast<char*>(&ch.blockOffset),
977 sizeof(ch.blockOffset));
978 stream.read(reinterpret_cast<char*>(&ch.brrHeader), sizeof(ch.brrHeader));
979 read_bool(&ch.useNoise);
980 stream.read(reinterpret_cast<char*>(&ch.startDelay), sizeof(ch.startDelay));
981 stream.read(reinterpret_cast<char*>(ch.adsrRates), sizeof(ch.adsrRates));
982 stream.read(reinterpret_cast<char*>(&ch.adsrState), sizeof(ch.adsrState));
983 stream.read(reinterpret_cast<char*>(&ch.sustainLevel),
984 sizeof(ch.sustainLevel));
985 stream.read(reinterpret_cast<char*>(&ch.gainSustainLevel),
986 sizeof(ch.gainSustainLevel));
987 read_bool(&ch.useGain);
988 stream.read(reinterpret_cast<char*>(&ch.gainMode), sizeof(ch.gainMode));
989 read_bool(&ch.directGain);
990 stream.read(reinterpret_cast<char*>(&ch.gainValue), sizeof(ch.gainValue));
991 stream.read(reinterpret_cast<char*>(&ch.preclampGain),
992 sizeof(ch.preclampGain));
993 stream.read(reinterpret_cast<char*>(&ch.gain), sizeof(ch.gain));
994 read_bool(&ch.keyOn);
995 read_bool(&ch.keyOff);
996 stream.read(reinterpret_cast<char*>(&ch.sampleOut), sizeof(ch.sampleOut));
997 stream.read(reinterpret_cast<char*>(&ch.volumeL), sizeof(ch.volumeL));
998 stream.read(reinterpret_cast<char*>(&ch.volumeR), sizeof(ch.volumeR));
999 read_bool(&ch.echoEnable);
1000 };
1001 for (auto& ch : channel) {
1002 read_channel(ch);
1003 }
1004
1005 stream.read(reinterpret_cast<char*>(&counter), sizeof(counter));
1006 stream.read(reinterpret_cast<char*>(&dirPage), sizeof(dirPage));
1007 stream.read(reinterpret_cast<char*>(&evenCycle), sizeof(evenCycle));
1008 stream.read(reinterpret_cast<char*>(&mute), sizeof(mute));
1009 stream.read(reinterpret_cast<char*>(&reset), sizeof(reset));
1010 stream.read(reinterpret_cast<char*>(&masterVolumeL), sizeof(masterVolumeL));
1011 stream.read(reinterpret_cast<char*>(&masterVolumeR), sizeof(masterVolumeR));
1012
1013 stream.read(reinterpret_cast<char*>(&sampleOutL), sizeof(sampleOutL));
1014 stream.read(reinterpret_cast<char*>(&sampleOutR), sizeof(sampleOutR));
1015 stream.read(reinterpret_cast<char*>(&echoOutL), sizeof(echoOutL));
1016 stream.read(reinterpret_cast<char*>(&echoOutR), sizeof(echoOutR));
1017
1018 stream.read(reinterpret_cast<char*>(&noiseSample), sizeof(noiseSample));
1019 stream.read(reinterpret_cast<char*>(&noiseRate), sizeof(noiseRate));
1020
1021 stream.read(reinterpret_cast<char*>(&echoWrites), sizeof(echoWrites));
1022 stream.read(reinterpret_cast<char*>(&echoVolumeL), sizeof(echoVolumeL));
1023 stream.read(reinterpret_cast<char*>(&echoVolumeR), sizeof(echoVolumeR));
1024 stream.read(reinterpret_cast<char*>(&feedbackVolume), sizeof(feedbackVolume));
1025 stream.read(reinterpret_cast<char*>(&echoBufferAdr), sizeof(echoBufferAdr));
1026 stream.read(reinterpret_cast<char*>(&echoDelay), sizeof(echoDelay));
1027 stream.read(reinterpret_cast<char*>(&echoLength), sizeof(echoLength));
1028 stream.read(reinterpret_cast<char*>(&echoBufferIndex), sizeof(echoBufferIndex));
1029 stream.read(reinterpret_cast<char*>(&firBufferIndex), sizeof(firBufferIndex));
1030
1031 stream.read(reinterpret_cast<char*>(firValues), sizeof(firValues));
1032 stream.read(reinterpret_cast<char*>(firBufferL), sizeof(firBufferL));
1033 stream.read(reinterpret_cast<char*>(firBufferR), sizeof(firBufferR));
1034
1035 stream.read(reinterpret_cast<char*>(&lastFrameBoundary), sizeof(lastFrameBoundary));
1036}
1037
1038} // namespace emu
1039} // namespace yaze
uint16_t echoBufferIndex
Definition dsp.h:193
uint32_t lastFrameBoundary
Definition dsp.h:198
void CycleChannel(int ch)
Definition dsp.cc:252
void HandleGain(int ch)
Definition dsp.cc:353
void GetSamples(int16_t *sample_data, int samples_per_frame, bool pal_timing)
Definition dsp.cc:722
int16_t sampleOutR
Definition dsp.h:179
void DecodeBrr(int ch)
Definition dsp.cc:432
int16_t echoOutR
Definition dsp.h:181
int8_t feedbackVolume
Definition dsp.h:189
void ResetSampleBuffer()
Definition dsp.cc:134
uint8_t Read(uint8_t adr)
Definition dsp.cc:483
std::vector< uint8_t > & aram_
Definition dsp.h:163
uint8_t noiseRate
Definition dsp.h:184
bool CheckCounter(int rate)
Definition dsp.cc:192
int16_t sampleBuffer[0x800 *2]
Definition dsp.h:158
uint16_t counter
Definition dsp.h:170
uint16_t sampleOffset
Definition dsp.h:159
int CopyNativeFrame(int16_t *sample_data, bool pal_timing)
Definition dsp.cc:848
uint16_t echoBufferAdr
Definition dsp.h:190
void Cycle()
Definition dsp.cc:142
int8_t masterVolumeL
Definition dsp.h:175
uint16_t echoDelay
Definition dsp.h:191
void HandleEcho()
Definition dsp.cc:198
bool debug_mute_channels_[8]
Definition dsp.h:161
int8_t firValues[8]
Definition dsp.h:195
int16_t sampleOutL
Definition dsp.h:178
void Reset()
Definition dsp.cc:68
void Write(uint8_t adr, uint8_t val)
Definition dsp.cc:487
int8_t masterVolumeR
Definition dsp.h:176
bool evenCycle
Definition dsp.h:172
InterpolationType interpolation_type
Definition dsp.h:153
uint8_t firBufferIndex
Definition dsp.h:194
void NewFrame()
Definition dsp.cc:130
int16_t firBufferR[8]
Definition dsp.h:197
int16_t noiseSample
Definition dsp.h:183
uint16_t dirPage
Definition dsp.h:171
int16_t echoOutL
Definition dsp.h:180
int16_t firBufferL[8]
Definition dsp.h:196
uint16_t echoLength
Definition dsp.h:192
int8_t echoVolumeR
Definition dsp.h:188
bool echoWrites
Definition dsp.h:186
void LoadState(std::istream &stream)
Definition dsp.cc:957
int8_t echoVolumeL
Definition dsp.h:187
bool mute
Definition dsp.h:173
uint8_t ram[0x80]
Definition dsp.h:166
void HandleNoise()
Definition dsp.cc:476
int16_t GetSample(int ch)
Definition dsp.cc:417
DspChannel channel[8]
Definition dsp.h:168
void SaveState(std::ostream &stream)
Definition dsp.cc:868
bool reset
Definition dsp.h:174
int16_t InterpolateCubic(int16_t p0, int16_t p1, int16_t p2, int16_t p3, double t)
Definition dsp.cc:676
int16_t InterpolateLinear(int16_t s0, int16_t s1, double frac)
Definition dsp.cc:701
int16_t InterpolateHermite(int16_t p0, int16_t p1, int16_t p2, int16_t p3, double t)
Definition dsp.cc:707
int16_t InterpolateCosine(int16_t s0, int16_t s1, double mu)
Definition dsp.cc:695
uint16_t pitch
Definition dsp.h:20
uint8_t startDelay
Definition dsp.h:31
uint8_t adsrState
Definition dsp.h:34
uint16_t pitchCounter
Definition dsp.h:21
uint16_t gain
Definition dsp.h:42
int16_t sampleOut
Definition dsp.h:47
uint16_t decodeOffset
Definition dsp.h:27
uint8_t bufferOffset
Definition dsp.h:25
uint8_t sustainLevel
Definition dsp.h:35
int16_t decodeBuffer[12]
Definition dsp.h:24
uint8_t blockOffset
Definition dsp.h:28
uint8_t brrHeader
Definition dsp.h:29
bool pitchModulation
Definition dsp.h:22
uint16_t gainValue
Definition dsp.h:40
uint8_t adsrRates[4]
Definition dsp.h:33
uint8_t gainMode
Definition dsp.h:38
uint16_t preclampGain
Definition dsp.h:41
uint8_t gainSustainLevel
Definition dsp.h:36