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