|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - sound.c
3:
1.1.1.19 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.11 root 7: This is where we emulate the YM2149. To obtain cycle-accurate timing we store
8: the current cycle time and this is incremented during each instruction.
9: When a write occurs in the PSG registers we take the difference in time and
10: generate this many samples using the previous register data.
11: Now we begin again from this point. To make sure we always have 1/50th of
12: samples we update the buffer generation every 1/50th second, just in case no
13: write took place on the PSG.
14: NOTE: If the emulator runs slower than 50fps it cannot update the buffers,
15: but the sound thread still needs some data to play to prevent a 'pop'. The
16: ONLY feasible solution is to play the same buffer again. I have tried all
17: kinds of methods to play the sound 'slower', but this produces un-even timing
18: in the sound and it simply doesn't work. If the emulator cannot keep the
19: speed, users will have to turn off the sound - that's it.
1.1.1.12 root 20:
1.1.1.20! root 21: The new version of the sound core uses/used some code/ideas from the following GPL projects :
1.1.1.15 root 22: - tone and noise steps computations are from StSound 1.2 by Arnaud Carré (Leonard/Oxygene)
1.1.1.20! root 23: (not used since Hatari 1.1.0)
1.1.1.12 root 24: - 5 bits volume table and 16*16*16 combinations of all volume are from Sc68 by Benjamin Gerard
25: - 4 bits to 5 bits volume interpolation from 16*16*16 to 32*32*32 from YM blep synthesis by Antti Lankila
26:
1.1.1.16 root 27: Special case for per==0 : as measured on a real STF, when tone/noise/env's per==0, we get
28: the same sound output as when per==1.
29:
30:
1.1 root 31: */
1.1.1.12 root 32:
33: /* 2008/05/05 [NP] Fix case where period is 0 for noise, sound or envelope. */
34: /* In that case, a real ST sounds as if period was in fact 1. */
35: /* (fix buggy sound replay in ESwat that set volume<0 and trigger */
36: /* a badly initialised envelope with envper=0). */
37: /* 2008/07/27 [NP] Better separation between accesses to the YM hardware registers */
38: /* and the sound rendering routines. Use Sound_WriteReg() to pass */
39: /* all writes to the sound rendering functions. This allows to */
1.1.1.19 root 40: /* have sound.c independent of psg.c (to ease replacement of */
1.1.1.12 root 41: /* sound.c by another rendering method). */
42: /* 2008/08/02 [NP] Initial convert of Ym2149Ex.cpp from C++ to C. */
43: /* Remove unused part of the code (StSound specific). */
44: /* 2008/08/09 [NP] Complete integration of StSound routines into sound.c */
45: /* Set EnvPer=3 if EnvPer<3 (ESwat buggy replay). */
46: /* 2008/08/13 [NP] StSound was generating samples in the range 0-32767, instead */
47: /* of really signed samples between -32768 and 32767, which could */
48: /* give incorrect results in many case. */
49: /* 2008/09/06 [NP] Use sc68 volumes table for a more accurate mixing of the voices */
50: /* All volumes are converted to 5 bits and the table contains */
51: /* 32*32*32 values. Samples are signed and centered to get the */
52: /* biggest amplitude possible. */
53: /* Faster mixing routines for tone+volume+envelope (don't use */
54: /* StSound's version anymore, it gave problem with some GCC). */
55: /* 2008/09/17 [NP] Add ym_normalise_5bit_table to normalise the 32*32*32 table and */
56: /* to optionally center 16 bit signed sample. */
57: /* Possibility to mix volumes using a table measured on ST or a */
58: /* linear mean of the 3 channels' volume. */
59: /* Default mixing set to YM_LINEAR_MIXING. */
60: /* 2008/10/14 [NP] Full support for 5 bits volumes : envelopes are generated with */
61: /* 32 volumes per pattern as on a real YM-2149. Fixed volumes */
62: /* on 4 bits are converted to their 5 bits equivalent. This should */
63: /* give the maximum accuracy possible when computing volumes. */
64: /* New version of Ym2149_EnvStepCompute to handle 5 bits volumes. */
65: /* Function YM2149_EnvBuild to compute the 96 volumes that define */
66: /* a single envelope (32 initial volumes, then 64 repeated values).*/
67: /* 2008/10/26 [NP] Correctly save/restore all necessary variables in */
68: /* Sound_MemorySnapShot_Capture. */
69: /* 2008/11/23 [NP] Clean source, remove old sound core. */
1.1.1.17 root 70: /* 2011/11/03 [DS] Stereo DC filtering which accounts for DMA sound. */
1.1.1.12 root 71:
72:
73:
1.1.1.14 root 74: const char Sound_fileid[] = "Hatari sound.c : " __DATE__ " " __TIME__;
1.1.1.5 root 75:
76: #include <SDL_types.h>
1.1 root 77:
78: #include "main.h"
79: #include "audio.h"
1.1.1.10 root 80: #include "cycles.h"
1.1.1.15 root 81: #include "configuration.h"
1.1.1.9 root 82: #include "dmaSnd.h"
1.1.1.15 root 83: #include "crossbar.h"
1.1 root 84: #include "file.h"
1.1.1.15 root 85: #include "cycInt.h"
1.1.1.8 root 86: #include "log.h"
1.1 root 87: #include "memorySnapShot.h"
88: #include "psg.h"
89: #include "sound.h"
1.1.1.16 root 90: #include "screen.h"
1.1 root 91: #include "video.h"
92: #include "wavFormat.h"
93: #include "ymFormat.h"
1.1.1.15 root 94: #include "avi_record.h"
1.1.1.16 root 95: #include "clocks_timings.h"
1.1 root 96:
97:
98:
1.1.1.12 root 99: /*--------------------------------------------------------------*/
100: /* Definition of the possible envelopes shapes (using 5 bits) */
101: /*--------------------------------------------------------------*/
102:
103: #define ENV_GODOWN 0 /* 31 -> 0 */
104: #define ENV_GOUP 1 /* 0 -> 31 */
105: #define ENV_DOWN 2 /* 0 -> 0 */
106: #define ENV_UP 3 /* 31 -> 31 */
107:
108: /* To generate an envelope, we first use block 0, then we repeat blocks 1 and 2 */
109: static const int YmEnvDef[ 16 ][ 3 ] = {
110: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 0 \___ */
111: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 1 \___ */
112: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 2 \___ */
113: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 3 \___ */
114: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 4 /___ */
115: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 5 /___ */
116: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 6 /___ */
117: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 7 /___ */
118: { ENV_GODOWN, ENV_GODOWN, ENV_GODOWN } , /* 8 \\\\ */
119: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 9 \___ */
120: { ENV_GODOWN, ENV_GOUP, ENV_GODOWN } , /* A \/\/ */
121: { ENV_GODOWN, ENV_UP, ENV_UP } , /* B \--- */
122: { ENV_GOUP, ENV_GOUP, ENV_GOUP } , /* C //// */
123: { ENV_GOUP, ENV_UP, ENV_UP } , /* D /--- */
124: { ENV_GOUP, ENV_GODOWN, ENV_GOUP } , /* E /\/\ */
125: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* F /___ */
126: };
127:
128:
129: /* Buffer to store the 16 envelopes built from YmEnvDef */
130: static ymu16 YmEnvWaves[ 16 ][ 32 * 3 ]; /* 16 envelopes with 3 blocks of 32 volumes */
1.1.1.3 root 131:
1.1 root 132:
1.1.1.12 root 133:
134: /*--------------------------------------------------------------*/
135: /* Definition of the volumes tables (using 5 bits) and of the */
136: /* mixing parameters for the 3 voices. */
137: /*--------------------------------------------------------------*/
138:
139: /* Table of unsigned 5 bit D/A output level for 1 channel as measured on a real ST (expanded from 4 bits to 5 bits) */
140: /* Vol 0 should be 310 when measuread as a voltage, but we set it to 0 in order to have a volume=0 matching */
141: /* the 0 level of a 16 bits unsigned sample (no sound output) */
142: static const ymu16 ymout1c5bit[ 32 ] =
143: {
144: 0 /*310*/, 369, 438, 521, 619, 735, 874, 1039,
145: 1234, 1467, 1744, 2072, 2463, 2927, 3479, 4135,
146: 4914, 5841, 6942, 8250, 9806,11654,13851,16462,
147: 19565,23253,27636,32845,39037,46395,55141,65535
1.1 root 148: };
149:
1.1.1.12 root 150: /* Convert a constant 4 bits volume to the internal 5 bits value : */
1.1.1.18 root 151: /* volume5=volume4*2+1, except for volumes 0 and 1 which remain 0 and 1, */
1.1.1.12 root 152: /* in order to map [0,15] into [0,31] (O must remain 0, and 15 must give 31) */
1.1.1.18 root 153: static const ymu16 YmVolume4to5[ 16 ] = { 0,1,5,7,9,11,13,15,17,19,21,23,25,27,29,31 };
1.1 root 154:
1.1.1.12 root 155: /* Table of unsigned 4 bit D/A output level for 3 channels as measured on a real ST */
1.1.1.18 root 156: static ymu16 volumetable_original[16][16][16] =
1.1.1.12 root 157: #include "ym2149_fixed_vol.h"
1.1.1.5 root 158:
1.1.1.12 root 159: /* Corresponding table interpolated to 5 bit D/A output level (16 bits unsigned) */
1.1.1.18 root 160: static ymu16 ymout5_u16[32][32][32];
1.1.1.12 root 161:
162: /* Same table, after conversion to signed results (same pointer, with different type) */
163: static yms16 *ymout5 = (yms16 *)ymout5_u16;
164:
165:
166:
167: /*--------------------------------------------------------------*/
168: /* Other constants / macros */
169: /*--------------------------------------------------------------*/
170:
171: /* Number of generated samples per frame (eg. 44Khz=882) */
1.1.1.16 root 172: #define SAMPLES_PER_FRAME (nAudioFrequency/nScreenRefreshRate)
1.1.1.12 root 173:
174: /* Current sound replay freq (usually 44100 Hz) */
1.1.1.14 root 175: #define YM_REPLAY_FREQ nAudioFrequency
1.1.1.12 root 176:
1.1.1.16 root 177: /* YM-2149 clock on all Atari models is 2 MHz */
178: #define YM_ATARI_CLOCK (MachineClocks.YM_Freq)
1.1.1.12 root 179:
180:
181: /* Merge/read the 3 volumes in a single integer (5 bits per volume) */
182: #define YM_MERGE_VOICE(C,B,A) ( (C)<<10 | (B)<<5 | A )
183: #define YM_MASK_1VOICE 0x1f
184: #define YM_MASK_A 0x1f
185: #define YM_MASK_B (0x1f<<5)
186: #define YM_MASK_C (0x1f<<10)
187:
188:
189: /* Constants for YM2149_Normalise_5bit_Table */
190: #define YM_OUTPUT_LEVEL 0x7fff /* amplitude of the final signal (0..65535 if centered, 0..32767 if not) */
1.1.1.14 root 191: #define YM_OUTPUT_CENTERED false
1.1.1.12 root 192:
193:
194:
195: /*--------------------------------------------------------------*/
196: /* Variables for the YM2149 emulator (need to be saved and */
197: /* restored in memory snapshots) */
198: /*--------------------------------------------------------------*/
199:
200: static ymu32 stepA , stepB , stepC;
201: static ymu32 posA , posB , posC;
202: static ymu32 mixerTA , mixerTB , mixerTC;
203: static ymu32 mixerNA , mixerNB , mixerNC;
204:
205: static ymu32 noiseStep;
206: static ymu32 noisePos;
207: static ymu32 currentNoise;
208: static ymu32 RndRack; /* current random seed */
209:
210: static ymu32 envStep;
211: static ymu32 envPos;
212: static int envShape;
213:
214: static ymu16 EnvMask3Voices = 0; /* mask is 0x1f for voices having an active envelope */
215: static ymu16 Vol3Voices = 0; /* volume 0-0x1f for voices having a constant volume */
216: /* volume is set to 0 if voice has an envelope in EnvMask3Voices */
217:
218:
219: /* Global variables that can be changed/read from other parts of Hatari */
220: Uint8 SoundRegs[ 14 ];
221:
1.1.1.16 root 222: int YmVolumeMixing = YM_TABLE_MIXING;
1.1.1.14 root 223: bool UseLowPassFilter = false;
1.1.1.12 root 224:
225: bool bEnvelopeFreqFlag; /* Cleared each frame for YM saving */
226:
227: Sint16 MixBuffer[MIXBUFFER_SIZE][2];
228: int nGeneratedSamples; /* Generated samples since audio buffer update */
229: static int ActiveSndBufIdx; /* Current working index into above mix buffer */
1.1.1.16 root 230: static int ActiveSndBufIdxAvi; /* Current working index to save an AVI audio frame */
231:
232: static yms64 SamplesPerFrame_unrounded = 0; /* Number of samples for the current VBL, with simulated fractional part */
233: static int SamplesPerFrame; /* Number of samples to generate for the current VBL */
234: static int CurrentSamplesNb = 0; /* Number of samples already generated for the current VBL */
1.1.1.12 root 235:
1.1.1.16 root 236: bool Sound_BufferIndexNeedReset = false;
1.1.1.12 root 237:
238:
239: /*--------------------------------------------------------------*/
240: /* Local functions prototypes */
241: /*--------------------------------------------------------------*/
242:
1.1.1.17 root 243: static ymsample LowPassFilter (ymsample x0);
1.1.1.18 root 244: static ymsample PWMaliasFilter (ymsample x0);
1.1.1.12 root 245:
1.1.1.18 root 246: static void interpolate_volumetable (ymu16 volumetable[32][32][32]);
1.1.1.12 root 247:
1.1.1.18 root 248: static void YM2149_BuildModelVolumeTable(ymu16 volumetable[32][32][32]);
249: static void YM2149_BuildLinearVolumeTable(ymu16 volumetable[32][32][32]);
1.1.1.12 root 250: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter);
251:
252: static void YM2149_EnvBuild (void);
1.1.1.16 root 253: static void Ym2149_BuildVolumeTable (void);
1.1.1.12 root 254: static void Ym2149_Init (void);
255: static void Ym2149_Reset (void);
256:
257: static ymu32 YM2149_RndCompute (void);
258: static ymu32 Ym2149_ToneStepCompute (ymu8 rHigh , ymu8 rLow);
259: static ymu32 Ym2149_NoiseStepCompute (ymu8 rNoise);
260: static ymu32 Ym2149_EnvStepCompute (ymu8 rHigh , ymu8 rLow);
261: static ymsample YM2149_NextSample (void);
262:
1.1.1.16 root 263: static int Sound_SetSamplesPassed(bool FillFrame);
264: static void Sound_GenerateSamples(int SamplesToGenerate);
1.1.1.12 root 265:
266:
267:
268: /*--------------------------------------------------------------*/
1.1.1.17 root 269: /* DC Adjuster */
1.1.1.12 root 270: /*--------------------------------------------------------------*/
271:
1.1.1.17 root 272: /**
273: * 6dB/octave first order HPF fc = (1.0-0.998)*44100/(2.0*pi)
274: * Z pole = 0.99804 --> FS = 44100 Hz : fc=13.7 Hz (11 Hz meas)
275: * a = (int32_t)(32768.0*(1.0 - pole)) : a = 64 !!!
276: * Input range: -32768 to 32767 Maximum step: +65536 or -65472
277: */
278: ymsample Subsonic_IIR_HPF_Left(ymsample x0)
1.1.1.12 root 279: {
1.1.1.17 root 280: static yms32 x1 = 0, y1 = 0, y0 = 0;
1.1.1.14 root 281:
1.1.1.17 root 282: y1 += ((x0 - x1)<<15) - (y0<<6); /* 64*y0 */
283: y0 = y1>>15;
284: x1 = x0;
1.1.1.12 root 285:
1.1.1.17 root 286: return y0;
1.1.1.12 root 287: }
288:
289:
1.1.1.17 root 290: ymsample Subsonic_IIR_HPF_Right(ymsample x0)
1.1 root 291: {
1.1.1.17 root 292: static yms32 x1 = 0, y1 = 0, y0 = 0;
1.1.1.12 root 293:
1.1.1.17 root 294: y1 += ((x0 - x1)<<15) - (y0<<6); /* 64*y0 */
295: y0 = y1>>15;
296: x1 = x0;
1.1.1.12 root 297:
1.1.1.17 root 298: return y0;
1.1.1.12 root 299: }
300:
301:
1.1.1.17 root 302: /*--------------------------------------------------------------*/
303: /* Low Pass Filter routines. */
304: /*--------------------------------------------------------------*/
1.1.1.12 root 305:
1.1.1.17 root 306: /**
307: * Get coefficients for different Fs (C10 is in ST only):
308: * Wc = 2*M_PI*4895.1;
309: * Fs = 44100;
310: * warp = Wc/tanf((Wc/2)/Fs);
311: * b = Wc/(warp+Wc);
312: * a = (Wc-warp)/(warp+Wc);
313: *
314: * #define B_z (yms32)( 0.2667*(1<<15))
315: * #define A_z (yms32)(-0.4667*(1<<15))
316: *
317: * y0 = (B_z*(x0 + x1) - A_z*y0) >> 15;
318: * x1 = x0;
319: *
320: * The Lowpass Filter formed by C10 = 0.1 uF
321: * and
1.1.1.18 root 322: * R8=1k // 1k*(65119-46602)/65119 // R9=10k // R10=5.1k //
1.1.1.17 root 323: * (R12=470)*(100=Q1_HFE) = 206.865 ohms when YM2149 is High
324: * and
325: * R8=1k // R9=10k // R10=5.1k // (R12=470)*(100=Q1_HFE)
326: * = 759.1 ohms when YM2149 is Low
327: * High corner is 1/(2*pi*(0.1*10e-6)*206.865) fc = 7693.7 Hz
328: * Low corner is 1/(2*pi*(0.1*10e-6)*795.1) fc = 2096.6 Hz
329: * Notes:
330: * - using STF reference designators R8 R9 R10 C10 (from dec 1986 schematics)
331: * - using corresponding numbers from psgstrep and psgquart
332: * - 65119 is the largest value in Paulo's psgstrep table
333: * - 46602 is the largest value in Paulo's psgquart table
334: * - this low pass filter uses the highest cutoff frequency
335: * on the STf (a slightly lower frequency is reasonable).
336: *
337: * A first order lowpass filter with a high cutoff frequency
338: * is used when the YM2149 pulls high, and a lowpass filter
339: * with a low cutoff frequency is used when R8 pulls low.
340: */
341: static ymsample LowPassFilter(ymsample x0)
342: {
343: static yms32 y0 = 0, x1 = 0;
344:
345: if (x0 >= y0)
346: /* YM Pull up: fc = 7586.1 Hz (44.1 KHz), fc = 8257.0 Hz (48 KHz) */
347: y0 = (3*(x0 + x1) + (y0<<1)) >> 3;
348: else
349: /* R8 Pull down: fc = 1992.0 Hz (44.1 KHz), fc = 2168.0 Hz (48 KHz) */
350: y0 = ((x0 + x1) + (6*y0)) >> 3;
1.1.1.12 root 351:
1.1.1.17 root 352: x1 = x0;
353: return y0;
1.1.1.12 root 354: }
355:
1.1.1.18 root 356: /**
357: * This piecewise selective filter works by filtering the falling
358: * edge of a sampled pulse-wave differently from the rising edge.
359: *
360: * Piecewise selective filtering is effective because harmonics on
361: * one part of a wave partially define harmonics on other portions.
362: *
363: * Piecewise selective filtering can efficiently reduce aliasing
364: * with minimal harmonic removal.
365: *
366: * I disclose this information into the public domain so that it
367: * cannot be patented. May 23 2012 David Savinkoff.
368: */
369: static ymsample PWMaliasFilter(ymsample x0)
370: {
371: static yms32 y0 = 0, x1 = 0;
372:
373: if (x0 >= y0)
374: /* YM Pull up */
375: y0 = x0;
376: else
377: /* R8 Pull down */
378: y0 = (3*(x0 + x1) + (y0<<1)) >> 3;
379:
380: x1 = x0;
381: return y0;
382: }
383:
1.1.1.12 root 384:
385:
386: /*--------------------------------------------------------------*/
387: /* Build the volume conversion table used to simulate the */
388: /* behaviour of DAC used with the YM2149 in the atari ST. */
389: /* The final 32*32*32 table is built using a 16*16*16 table */
390: /* of all possible fixed volume combinations on a ST. */
391: /*--------------------------------------------------------------*/
392:
1.1.1.18 root 393: static void interpolate_volumetable(ymu16 volumetable[32][32][32])
1.1.1.12 root 394: {
1.1.1.18 root 395: int i, j, k;
1.1.1.12 root 396:
1.1.1.18 root 397: for (i = 1; i < 32; i += 2) { /* Copy 16 Panels to make a Block */
398: for (j = 1; j < 32; j += 2) { /* Copy 16 Rows to make a Panel */
399: for (k = 1; k < 32; k += 2) { /* Copy 16 Elements to make a Row */
400: volumetable[i][j][k] = volumetable_original[(i-1)/2][(j-1)/2][(k-1)/2];
1.1.1.12 root 401: }
1.1.1.18 root 402: volumetable[i][j][0] = volumetable[i][j][1]; /* Move 0th Element */
403: volumetable[i][j][1] = volumetable[i][j][3]; /* Move 1st Element */
404: /* Interpolate 3rd Element */
405: volumetable[i][j][3] = (ymu16)(0.5 + sqrt((double)volumetable[i][j][1] * volumetable[i][j][5]));
406: for (k = 2; k < 32; k += 2) /* Interpolate Even Elements */
407: volumetable[i][j][k] = (ymu16)(0.5 + sqrt((double)volumetable[i][j][k-1] * volumetable[i][j][k+1]));
1.1.1.12 root 408: }
1.1.1.18 root 409: for (k = 0; k < 32; k++) {
410: volumetable[i][0][k] = volumetable[i][1][k]; /* Move 0th Row */
411: volumetable[i][1][k] = volumetable[i][3][k]; /* Move 1st Row */
412: /* Interpolate 3rd Row */
413: volumetable[i][3][k] = (ymu16)(0.5 + sqrt((double)volumetable[i][1][k] * volumetable[i][5][k]));
414: }
415: for (j = 2; j < 32; j += 2) /* Interpolate Even Rows */
416: for (k = 0; k < 32; k++)
417: volumetable[i][j][k] = (ymu16)(0.5 + sqrt((double)volumetable[i][j-1][k] * volumetable[i][j+1][k]));
1.1.1.11 root 418: }
1.1.1.18 root 419: for (j = 0; j < 32; j++)
420: for (k = 0; k < 32; k++) {
421: volumetable[0][j][k] = volumetable[1][j][k]; /* Move 0th Panel */
422: volumetable[1][j][k] = volumetable[3][j][k]; /* Move 1st Panel */
423: /* Interpolate 3rd Panel */
424: volumetable[3][j][k] = (ymu16)(0.5 + sqrt((double)volumetable[1][j][k] * volumetable[5][j][k]));
425: }
426: for (i = 2; i < 32; i += 2) /* Interpolate Even Panels */
427: for (j = 0; j < 32; j++) /* Interpolate Even Panels */
428: for (k = 0; k < 32; k++)
429: volumetable[i][j][k] = (ymu16)(0.5 + sqrt((double)volumetable[i-1][j][k] * volumetable[i+1][j][k]));
1.1 root 430: }
431:
1.1.1.5 root 432:
1.1.1.12 root 433:
434:
1.1.1.2 root 435: /*-----------------------------------------------------------------------*/
1.1.1.11 root 436: /**
1.1.1.12 root 437: * Build a linear version of the conversion table.
438: * We use the mean of the 3 volumes converted to 16 bit values
439: * (each value of ymout1c5bit is in [0,65535])
1.1.1.11 root 440: */
1.1.1.12 root 441:
1.1.1.18 root 442: static void YM2149_BuildLinearVolumeTable(ymu16 volumetable[32][32][32])
1.1 root 443: {
1.1.1.12 root 444: int i, j, k;
445:
446: for (i = 0; i < 32; i++)
447: for (j = 0; j < 32; j++)
448: for (k = 0; k < 32; k++)
1.1.1.18 root 449: volumetable[i][j][k] = (ymu16)( ((ymu32)ymout1c5bit[i] + ymout1c5bit[j] + ymout1c5bit[k]) / 3);
1.1.1.12 root 450: }
451:
452:
453:
1.1 root 454:
1.1.1.12 root 455: /*-----------------------------------------------------------------------*/
456: /**
1.1.1.17 root 457: * Build a circuit analysed version of the conversion table.
458: * David Savinkoff designed this algorithm by analysing data
459: * measured by Paulo Simoes and Benjamin Gerard.
460: * The numbers are arrived at by assuming a current steering
461: * resistor ladder network and using the voltage divider rule.
1.1.1.18 root 462: *
463: * If one looks at the ST schematic of the YM2149, one sees
464: * three sound pins tied together and attached to a 1000 ohm
465: * resistor (1k) that has the other end grounded.
466: * The 1k resistor is also in parallel with a 0.1 microfarad
467: * capacitor (on the Atari ST, not STE or others). The voltage
468: * developed across the 1K resistor is the output voltage which
469: * I call Vout.
470: *
1.1.1.19 root 471: * The output of the YM2149 is modelled well as pullup resistors.
1.1.1.18 root 472: * Thus, the three sound pins are seen as three parallel
473: * computer-controlled, adjustable pull-up resistors.
474: * To emulate the output of the YM2149, one must determine the
475: * resistance values of the YM2149 relative to the 1k resistor,
476: * which is done by the 'math model'.
477: *
478: * The AC + DC math model is:
479: *
480: * (MaxVol*WARP) / (1.0 + 1.0/(conductance_[i]+conductance_[j]+conductance_[k]))
481: * or
482: * (MaxVol*WARP) / (1.0 + 1.0/( 1/Ra +1/Rb +1/Rc )) , Ra = channel A resistance
483: *
484: * Note that the first 1.0 in the formula represents the
485: * normalized 1k resistor (1.0 * 1000 ohms = 1k).
486: *
487: * The YM2149 DC component model represents the output voltage
488: * filtered of high frequency AC component, but DC component
489: * remains.
490: * The YM2149 DC component mode treats the voltage exactly as if
491: * it were low pass filtered. This is more than what is required
492: * to make 'quartet mode sound'. Simplicity leads to Generality!
493: *
494: * The DC component model model is:
495: *
496: * (MaxVol*WARP) / (2.0 + 1.0/( 1/Ra + 1/Rb + 1/Rc))
497: * or
498: * (MaxVol*WARP*0.5) / (1.0 + 0.5/( 1/Ra + 1/Rb + 1/Rc))
499: *
500: * Note that the 1.0 represents the normalized 1k resistor.
501: * 0.5 represents 50% duty cycle for the parallel resistors
502: * being summed (this effectively doubles the pull-up resistance).
1.1.1.17 root 503: */
504:
1.1.1.18 root 505: static void YM2149_BuildModelVolumeTable(ymu16 volumetable[32][32][32])
1.1.1.17 root 506: {
1.1.1.18 root 507: #define MaxVol 65535.0 /* Normal Mode Maximum value in table */
508: #define FOURTH2 1.19 /* Fourth root of two from YM2149 */
509: #define WARP 1.666666666666666667 /* measured as 1.65932 from 46602 */
1.1.1.17 root 510:
511: double conductance;
512: double conductance_[32];
513: int i, j, k;
514:
515: /**
516: * YM2149 and R8=1k follows (2^-1/4)^(n-31) better when 2 voices are
517: * summed (A+B or B+C or C+A) rather than individually (A or B or C):
1.1.1.18 root 518: * conductance = 2.0/3.0/(1.0-1.0/WARP)-2.0/3.0;
1.1.1.17 root 519: * When taken into consideration with three voices.
520: *
521: * Note that the YM2149 does not use laser trimmed resistances, thus
522: * has offsets that are added and/or multiplied with (2^-1/4)^(n-31).
523: */
1.1.1.18 root 524: conductance = 2.0/3.0/(1.0-1.0/WARP)-2.0/3.0; /* conductance = 1.0 */
1.1.1.17 root 525:
526: /**
527: * Because the YM current output (voltage source with series resistances)
528: * is connected to a grounded resistor to develop the output voltage
529: * (instead of a current to voltage converter), the output transfer
530: * function is not linear. Thus:
531: * 2.0*conductance_[n] = 1.0/(1.0-1.0/FOURTH2/(1.0/conductance + 1.0))-1.0;
532: */
533: for (i = 31; i >= 1; i--)
534: {
535: conductance_[i] = conductance/2.0;
536: conductance = 1.0/(1.0-1.0/FOURTH2/(1.0/conductance + 1.0))-1.0;
537: }
1.1.1.18 root 538: conductance_[0] = 1.0e-8; /* Avoid divide by zero */
1.1.1.17 root 539:
1.1.1.18 root 540: /**
541: * YM2149 AC + DC components model:
542: * (Note that Maxvol is 65119 in Simoes' table, 65535 in Gerard's)
543: *
544: * Sum the conductances as a function of a voltage divider:
545: * Vout=Vin*Rout/(Rout+Rin)
546: */
1.1.1.17 root 547: for (i = 0; i < 32; i++)
548: for (j = 0; j < 32; j++)
549: for (k = 0; k < 32; k++)
550: {
1.1.1.18 root 551: volumetable[i][j][k] = (ymu16)(0.5+(MaxVol*WARP)/(1.0 +
1.1.1.17 root 552: 1.0/(conductance_[i]+conductance_[j]+conductance_[k])));
553: }
1.1.1.18 root 554:
555: /**
556: * YM2149 DC component model:
557: * R8=1k (pulldown) + YM//1K (pullup) with YM 50% duty PWM
558: * (Note that MaxVol is 46602 in Paulo Simoes Quartet mode table)
559: *
560: * for (i = 0; i < 32; i++)
561: * for (j = 0; j < 32; j++)
562: * for (k = 0; k < 32; k++)
563: * {
564: * volumetable[i][j][k] = (ymu16)(0.5+(MaxVol*WARP)/(1.0 +
565: * 2.0/(conductance_[i]+conductance_[j]+conductance_[k])));
566: * }
567: */
1.1.1.17 root 568: }
569:
570:
571:
572:
573: /*-----------------------------------------------------------------------*/
574: /**
1.1.1.12 root 575: * Normalise and optionally center the volume table used to
576: * convert the 3 volumes to a final signed 16 bit sample.
577: * This allows to adapt the amplitude/volume of the samples and
578: * to convert unsigned values to signed values.
579: * - in_5bit contains 32*32*32 unsigned values in the range
580: * [0,65535].
581: * - out_5bit will contain signed values
582: * Possible values are :
583: * Level=65535 and DoCenter=TRUE -> [-32768,32767]
1.1.1.14 root 584: * Level=32767 and DoCenter=false -> [0,32767]
1.1.1.19 root 585: * Level=16383 and DoCenter=false -> [0,16383] (to avoid overflow with DMA sound on STe)
1.1.1.12 root 586: */
587:
588: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter)
589: {
590: if ( Level )
1.1.1.11 root 591: {
1.1.1.14 root 592: int h;
1.1.1.12 root 593: int Max = in_5bit[0x7fff];
1.1.1.19 root 594: int Center = (Level+1)>>1;
1.1.1.14 root 595: //fprintf ( stderr , "level %d max %d center %d\n" , Level, Max, Center );
596:
1.1.1.12 root 597: /* Change the amplitude of the signal to 'level' : [0,max] -> [0,level] */
598: /* Then optionally center the signal around Level/2 */
599: /* This means we go from sthg like [0,65535] to [-32768, 32767] if Level=65535 and DoCenter=TRUE */
600: for (h=0; h<32*32*32; h++)
601: {
602: int tmp = in_5bit[h], res;
603: res = tmp * Level / Max;
1.1.1.14 root 604:
1.1.1.12 root 605: if ( DoCenter )
606: res -= Center;
607:
608: out_5bit[h] = res;
1.1.1.14 root 609: //fprintf ( stderr , "h %d in %d out %d\n" , h , tmp , res );
1.1.1.12 root 610: }
1.1.1.11 root 611: }
1.1 root 612: }
613:
1.1.1.5 root 614:
1.1.1.12 root 615:
616:
1.1.1.2 root 617: /*-----------------------------------------------------------------------*/
1.1.1.11 root 618: /**
1.1.1.12 root 619: * Precompute all 16 possible envelopes.
620: * Each envelope is made of 3 blocks of 32 volumes.
1.1.1.11 root 621: */
1.1.1.12 root 622:
623: static void YM2149_EnvBuild ( void )
1.1 root 624: {
1.1.1.12 root 625: int env;
626: int block;
627: int vol=0 , inc=0;
628: int i;
1.1 root 629:
1.1.1.12 root 630:
631: for ( env=0 ; env<16 ; env++ ) /* 16 possible envelopes */
632: for ( block=0 ; block<3 ; block++ ) /* 3 blocks to define an envelope */
633: {
1.1.1.14 root 634: switch ( YmEnvDef[ env ][ block ] )
635: {
1.1.1.12 root 636: case ENV_GODOWN : vol=31 ; inc=-1 ; break;
637: case ENV_GOUP : vol=0 ; inc=1 ; break;
638: case ENV_DOWN : vol=0 ; inc=0 ; break;
639: case ENV_UP : vol=31 ; inc=0 ; break;
1.1.1.14 root 640: }
641:
1.1.1.12 root 642: for ( i=0 ; i<32 ; i++ ) /* 32 volumes per block */
643: {
644: YmEnvWaves[ env ][ block*32 + i ] = YM_MERGE_VOICE ( vol , vol , vol );
645: vol += inc;
646: }
647: }
648: }
649:
650:
651:
652: /*-----------------------------------------------------------------------*/
653: /**
1.1.1.16 root 654: * Depending on the YM mixing method, build the table used to convert
655: * the 3 YM volumes into a single sample.
1.1.1.12 root 656: */
657:
1.1.1.16 root 658: static void Ym2149_BuildVolumeTable(void)
1.1.1.12 root 659: {
660: /* Depending on the volume mixing method, we use a table based on real measures */
661: /* or a table based on a linear volume mixing. */
1.1.1.17 root 662: if ( YmVolumeMixing == YM_MODEL_MIXING )
663: YM2149_BuildModelVolumeTable(ymout5_u16); /* create 32*32*32 circuit analysed model of the volume table */
664: else if ( YmVolumeMixing == YM_TABLE_MIXING )
1.1.1.16 root 665: interpolate_volumetable(ymout5_u16); /* expand the 16*16*16 values in volumetable_original to 32*32*32 */
1.1.1.12 root 666: else
667: YM2149_BuildLinearVolumeTable(ymout5_u16); /* combine the 32 possible volumes */
668:
669: /* Normalise/center the values (convert from u16 to s16) */
1.1.1.19 root 670: /* On STE/TT, we use YM_OUTPUT_LEVEL>>1 to avoid overflow with DMA sound */
671: if ( (ConfigureParams.System.nMachineType == MACHINE_STE) || (ConfigureParams.System.nMachineType == MACHINE_MEGA_STE)
672: || (ConfigureParams.System.nMachineType == MACHINE_TT) )
673: YM2149_Normalise_5bit_Table ( ymout5_u16[0][0] , ymout5 , (YM_OUTPUT_LEVEL>>1) , YM_OUTPUT_CENTERED );
674: else
675: YM2149_Normalise_5bit_Table ( ymout5_u16[0][0] , ymout5 , YM_OUTPUT_LEVEL , YM_OUTPUT_CENTERED );
1.1.1.16 root 676: }
677:
678:
679:
680: /*-----------------------------------------------------------------------*/
681: /**
682: * Init some internal tables for faster results (env, volume)
683: * and reset the internal states.
684: */
685:
686: static void Ym2149_Init(void)
687: {
688: /* Build the 16 envelope shapes */
689: YM2149_EnvBuild();
690:
691: /* Build the volume conversion table */
692: Ym2149_BuildVolumeTable();
1.1.1.12 root 693:
694: /* Reset YM2149 internal states */
695: Ym2149_Reset();
696: }
697:
698:
699:
700: /*-----------------------------------------------------------------------*/
701: /**
1.1.1.16 root 702: * Reset all ym registers as well as the internal variables
1.1.1.12 root 703: */
704:
705: static void Ym2149_Reset(void)
706: {
707: int i;
1.1.1.14 root 708:
1.1.1.12 root 709: for ( i=0 ; i<14 ; i++ )
710: Sound_WriteReg ( i , 0 );
711:
712: Sound_WriteReg ( 7 , 0xff );
713:
1.1.1.16 root 714: posA = 0;
715: posB = 0;
716: posC = 0;
717:
1.1.1.12 root 718: currentNoise = 0xffff;
1.1.1.14 root 719:
1.1.1.12 root 720: RndRack = 1;
1.1.1.14 root 721:
1.1.1.12 root 722: envShape = 0;
723: envPos = 0;
724: }
725:
726:
727:
728: /*-----------------------------------------------------------------------*/
729: /**
730: * Returns a pseudo random value, used to generate white noise.
1.1.1.19 root 731: * As measured by David Savinkoff, the YM2149 uses a 17 stage LSFR with
732: * 2 taps (17,14)
1.1.1.12 root 733: */
734:
735: static ymu32 YM2149_RndCompute(void)
736: {
1.1.1.19 root 737: /* 17 stage, 2 taps (17, 14) LFSR */
738: if (RndRack & 1)
739: {
740: RndRack = RndRack>>1 ^ 0x12000; /* bits 17 and 14 are ones */
741: return 0xffff;
742: }
743: else
744: { RndRack >>= 1;
745: return 0;
746: }
1.1.1.12 root 747: }
748:
749:
750:
751: /*-----------------------------------------------------------------------*/
752: /**
1.1.1.16 root 753: * Compute tone's step based on the input period.
754: * Although for tone we should have the same result when per==0 and per==1,
755: * this gives some very sharp and unpleasant sounds in the emulation.
756: * To get a better sound, we consider all per<=5 to give step=0, which will
757: * produce a constant output at value '1'. This should be handled with some
758: * proper filters to remove high frequencies as on a real ST (where per<=9
759: * gives nearly no audible sound).
760: * A common replay freq of 44.1 kHz will also not be high enough to correctly
761: * render possible tone's freq of 125 or 62.5 kHz (when per==1 or per==2)
1.1.1.12 root 762: */
763:
1.1.1.16 root 764: #define NEWSTEP
765: #ifndef NEWSTEP
1.1.1.12 root 766: static ymu32 Ym2149_ToneStepCompute(ymu8 rHigh , ymu8 rLow)
767: {
768: int per;
1.1.1.14 root 769: yms64 step;
1.1.1.12 root 770:
771: per = rHigh&15;
772: per = (per<<8)+rLow;
1.1.1.18 root 773:
774: if (per <= (int)(YM_ATARI_CLOCK/(YM_REPLAY_FREQ*7)) )
1.1.1.12 root 775: return 0;
776:
1.1.1.14 root 777: step = YM_ATARI_CLOCK;
1.1.1.12 root 778: step <<= (15+16-3);
779: step /= (per * YM_REPLAY_FREQ);
780:
781: return step;
782: }
1.1.1.16 root 783: #else
784: static ymu32 Ym2149_ToneStepCompute(ymu8 rHigh , ymu8 rLow)
785: {
786: int per;
787: yms64 step;
788:
789: per = rHigh&15;
790: per = (per<<8)+rLow;
791:
792: #if 0 /* need some high freq filters for this to work correctly */
793: if ( per == 0 )
794: per = 1; /* result for Per=0 is the same as for Per=1 */
795: #else
1.1.1.18 root 796: if (per <= (int)(YM_ATARI_CLOCK/(YM_REPLAY_FREQ*7)) )
797: return 0; /* discard frequencies higher than 80% of nyquist rate. */
1.1.1.16 root 798: #endif
799:
800: step = YM_ATARI_CLOCK;
801: step <<= 24;
802:
803: step /= (per * 8 * YM_REPLAY_FREQ); /* 0x5ab9 < step < 0x5ab3f46 at 44.1 kHz */
804:
805: return step;
806: }
807: #endif
1.1.1.12 root 808:
1.1.1.16 root 809: /*-----------------------------------------------------------------------*/
810: /**
811: * Compute noise's step based on the input period.
812: * On a real STF, we get the same result when per==0 and per==1.
813: * A common replay freq of 44.1 kHz will not be high enough to correctly
814: * render possible noise's freq of 125 or 62.5 kHz (when per==1 or per==2).
815: * With a random wave such as noise, this means that with a replay freq
816: * of 44.1 kHz, per==1 and per==2 (as well as per==3) will sound the same :
817: * per==1 step=0x2d59fa3 freq=125 kHz
818: * per==2 step=0x16acfd1 freq=62.5 kHz
819: * per==3 step=0x0f1dfe1 freq=41.7 kHz
820: */
1.1.1.12 root 821:
1.1.1.16 root 822: #ifndef NEWSTEP
1.1.1.12 root 823: static ymu32 Ym2149_NoiseStepCompute(ymu8 rNoise)
824: {
825: int per;
1.1.1.14 root 826: yms64 step;
1.1.1.12 root 827:
828: per = (rNoise&0x1f);
829: if (per<3)
830: return 0;
831:
1.1.1.14 root 832: step = YM_ATARI_CLOCK;
1.1.1.12 root 833: step <<= (16-1-3);
834: step /= (per * YM_REPLAY_FREQ);
835:
836: return step;
1.1 root 837: }
1.1.1.16 root 838: #else
839: static ymu32 Ym2149_NoiseStepCompute(ymu8 rNoise)
840: {
841: int per;
842: yms64 step;
843:
844: per = (rNoise&0x1f);
1.1 root 845:
1.1.1.16 root 846: if ( per == 0 )
847: per = 1; /* result for Per=0 is the same as for Per=1 */
848:
849: step = YM_ATARI_CLOCK;
850: step <<= 24;
851:
852: step /= (per * 16 * YM_REPLAY_FREQ); /* 0x17683f < step < 0x2d59fa3 at 44.1 kHz */
853:
854: return step;
855: }
856: #endif
1.1.1.5 root 857:
1.1.1.2 root 858: /*-----------------------------------------------------------------------*/
1.1.1.11 root 859: /**
1.1.1.12 root 860: * Compute envelope's step. The envelope is made of different patterns
861: * of 32 volumes. In each pattern, the volume is changed at frequency
862: * Fe = MasterClock / ( 8 * EnvPer ).
863: * In our case, we use a lower replay freq ; between 2 consecutive calls
864: * to envelope's generation, the internal counter will advance 'step'
865: * units, where step = MasterClock / ( 8 * EnvPer * YM_REPLAY_FREQ )
866: * As 'step' requires floating point to be stored, we use left shifting
867: * to multiply 'step' by a fixed amount. All operations are made with
868: * shifted values ; to get the final value, we must right shift the
869: * result. We use '<<24', which gives 8 bits for the integer part, and
870: * the equivalent of 24 bits for the fractional part.
871: * Since we're using large numbers, we temporarily use 64 bits integer
872: * to avoid overflow and keep largest precision possible.
1.1.1.16 root 873: * On a real STF, we get the same result when per==0 and per==1.
1.1.1.11 root 874: */
1.1.1.12 root 875:
876: static ymu32 Ym2149_EnvStepCompute(ymu8 rHigh , ymu8 rLow)
1.1 root 877: {
1.1.1.12 root 878: yms64 per;
1.1.1.14 root 879: yms64 step;
1.1 root 880:
1.1.1.12 root 881: per = rHigh;
882: per = (per<<8)+rLow;
883:
1.1.1.14 root 884: step = YM_ATARI_CLOCK;
1.1.1.12 root 885: step <<= 24;
1.1.1.16 root 886:
887: if ( per == 0 )
888: per = 1; /* result for Per=0 is the same as for Per=1 */
889:
890: step /= (8 * per * YM_REPLAY_FREQ); /* 0x5ab < step < 0x5ab3f46 at 44.1 kHz */
1.1.1.12 root 891:
892: return step;
893: }
894:
895:
896:
897: /*-----------------------------------------------------------------------*/
898: /**
899: * Main function : compute the value of the next sample.
900: * Mixes all 3 voices with tone+noise+env and apply low pass
901: * filter if needed.
1.1.1.16 root 902: * All operations are done with integer math, using <<24 to simulate
903: * floating point precision : upper 8 bits are the integer part, lower 24
904: * are the fractional part.
905: * Tone is a square wave with 2 states 0 or 1. If integer part of posX is
906: * even (bit24=0) we consider output is 0, else (bit24=1) we consider
907: * output is 1. This gives the value of bt for one voice after extending it
908: * to all 0 bits or all 1 bits using a '-'
1.1.1.12 root 909: */
910:
1.1.1.16 root 911: #ifndef NEWSTEP
1.1.1.12 root 912: static ymsample YM2149_NextSample(void)
913: {
914: ymsample sample;
915: int bt;
916: ymu32 bn;
917: ymu16 Env3Voices;
918: ymu16 Tone3Voices;
919:
920:
921: /* Noise value : 0 or 0xffff */
922: if ( noisePos&0xffff0000 )
923: {
1.1.1.19 root 924: currentNoise = YM2149_RndCompute();
1.1.1.12 root 925: noisePos &= 0xffff;
926: }
927: bn = currentNoise; /* 0 or 0xffff */
928:
929: /* Get the 5 bits volume corresponding to the current envelope's position */
930: Env3Voices = YmEnvWaves[ envShape ][ envPos>>24 ]; /* integer part of envPos is in bits 24-31 */
931: Env3Voices &= EnvMask3Voices; /* only keep volumes for voices using envelope */
932:
933: //fprintf ( stderr , "env %x %x %x\n" , Env3Voices , envStep , envPos );
934:
935: /* Tone3Voices will contain the output state of each voice : 0 or 0x1f */
936: bt = ((((yms32)posA)>>31) | mixerTA) & (bn | mixerNA); /* 0 or 0xffff */
937: Tone3Voices = bt & YM_MASK_1VOICE; /* 0 or 0x1f */
938: bt = ((((yms32)posB)>>31) | mixerTB) & (bn | mixerNB);
939: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 5;
940: bt = ((((yms32)posC)>>31) | mixerTC) & (bn | mixerNC);
941: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 10;
942:
943: /* Combine fixed volumes and envelope volumes and keep the resulting */
944: /* volumes depending on the output state of each voice (0 or 0x1f) */
945: Tone3Voices &= ( Env3Voices | Vol3Voices );
946:
1.1.1.18 root 947: /* When a step period is 0, the represented frequency was filtered from the */
948: /* ouput of the YM2149. Thus, use the transient DC component of the sample. */
949: /* Note that the "-1" table offset is a "good fit" for the DC component. */
950:
951: if (stepA == 0 && (Tone3Voices & YM_MASK_A) > 1)
952: Tone3Voices -= 1; /* Voice A AC component removed; Transient DC component remains */
953:
954: if (stepB == 0 && (Tone3Voices & YM_MASK_B) > 1<<5)
955: Tone3Voices -= 1<<5; /* Voice B AC component removed; Transient DC component remains */
956:
957: if (stepC == 0 && (Tone3Voices & YM_MASK_C) > 1<<10)
958: Tone3Voices -= 1<<10; /* Voice C AC component removed; Transient DC component remains */
959:
1.1.1.12 root 960: /* D/A conversion of the 3 volumes into a sample using a precomputed conversion table */
1.1.1.18 root 961:
1.1.1.12 root 962: sample = ymout5[ Tone3Voices ]; /* 16 bits signed value */
963:
964:
965: /* Increment positions */
966: posA += stepA;
967: posB += stepB;
968: posC += stepC;
969: noisePos += noiseStep;
1.1.1.14 root 970:
1.1.1.12 root 971: envPos += envStep;
972: if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
973: envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
974:
975: /* Apply low pass filter ? */
976: if ( UseLowPassFilter )
1.1.1.18 root 977: return LowPassFilter(sample);
978: else
979: return PWMaliasFilter(sample);
1.1 root 980: }
1.1.1.16 root 981: #else
982: static ymsample YM2149_NextSample(void)
983: {
984: ymsample sample;
985: ymu32 bt;
986: ymu32 bn;
987: ymu16 Env3Voices; /* 0x00CCBBAA */
988: ymu16 Tone3Voices; /* 0x00CCBBAA */
1.1 root 989:
990:
1.1.1.16 root 991: /* Noise value : 0 or 0xffff */
992: if ( noisePos&0xff000000 ) /* integer part > 0 */
993: {
1.1.1.19 root 994: currentNoise = YM2149_RndCompute();
1.1.1.16 root 995: noisePos &= 0xffffff; /* keep fractional part of noisePos */
996: }
997: bn = currentNoise; /* 0 or 0xffff */
998:
999: /* Get the 5 bits volume corresponding to the current envelope's position */
1000: Env3Voices = YmEnvWaves[ envShape ][ envPos>>24 ]; /* integer part of envPos is in bits 24-31 */
1001: Env3Voices &= EnvMask3Voices; /* only keep volumes for voices using envelope */
1002:
1003: //fprintf ( stderr , "env %x %x %x\n" , Env3Voices , envStep , envPos );
1004:
1005: /* Tone3Voices will contain the output state of each voice : 0 or 0x1f */
1006: bt = -( (posA>>24) & 1); /* 0 if bit24=0 or 0xffffffff if bit24=1 */
1007: bt = (bt | mixerTA) & (bn | mixerNA); /* 0 or 0xffff */
1008: Tone3Voices = bt & YM_MASK_1VOICE; /* 0 or 0x1f */
1009: bt = -( (posB>>24) & 1);
1010: bt = (bt | mixerTB) & (bn | mixerNB);
1011: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 5;
1012: bt = -( (posC>>24) & 1);
1013: bt = (bt | mixerTC) & (bn | mixerNC);
1014: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 10;
1015:
1016: /* Combine fixed volumes and envelope volumes and keep the resulting */
1017: /* volumes depending on the output state of each voice (0 or 0x1f) */
1018: Tone3Voices &= ( Env3Voices | Vol3Voices );
1019:
1020: /* D/A conversion of the 3 volumes into a sample using a precomputed conversion table */
1.1.1.18 root 1021:
1022: if (stepA == 0 && (Tone3Voices & YM_MASK_A) > 1)
1023: Tone3Voices -= 1; /* Voice A AC component removed; Transient DC component remains */
1024:
1025: if (stepB == 0 && (Tone3Voices & YM_MASK_B) > 1<<5)
1026: Tone3Voices -= 1<<5; /* Voice B AC component removed; Transient DC component remains */
1027:
1028: if (stepC == 0 && (Tone3Voices & YM_MASK_C) > 1<<10)
1029: Tone3Voices -= 1<<10; /* Voice C AC component removed; Transient DC component remains */
1030:
1.1.1.16 root 1031: sample = ymout5[ Tone3Voices ]; /* 16 bits signed value */
1032:
1033:
1034: /* Increment positions */
1035: posA += stepA;
1036: posB += stepB;
1037: posC += stepC;
1038: noisePos += noiseStep;
1039:
1040: envPos += envStep;
1041: if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
1042: envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
1043:
1044: /* Apply low pass filter ? */
1045: if ( UseLowPassFilter )
1.1.1.18 root 1046: return LowPassFilter(sample);
1047: else
1048: return PWMaliasFilter(sample);
1.1.1.16 root 1049: }
1050: #endif
1051:
1.1.1.12 root 1052:
1.1.1.2 root 1053: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1054: /**
1.1.1.12 root 1055: * Update internal variables (steps, volume masks, ...) each
1056: * time an YM register is changed.
1.1.1.11 root 1057: */
1.1.1.16 root 1058: #ifndef NEWSTEP
1059: #define BIT_SHIFT 31
1060: #else
1061: #define BIT_SHIFT 24
1062: #endif
1.1.1.12 root 1063: void Sound_WriteReg( int reg , Uint8 data )
1.1.1.7 root 1064: {
1.1.1.12 root 1065: switch (reg)
1066: {
1067: case 0:
1068: SoundRegs[0] = data;
1069: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
1.1.1.16 root 1070: if (!stepA) posA = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1071: break;
1072:
1073: case 1:
1074: SoundRegs[1] = data & 0x0f;
1075: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
1.1.1.16 root 1076: if (!stepA) posA = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1077: break;
1078:
1079: case 2:
1080: SoundRegs[2] = data;
1081: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
1.1.1.16 root 1082: if (!stepB) posB = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1083: break;
1.1.1.7 root 1084:
1.1.1.12 root 1085: case 3:
1086: SoundRegs[3] = data & 0x0f;
1087: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
1.1.1.16 root 1088: if (!stepB) posB = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1089: break;
1090:
1091: case 4:
1092: SoundRegs[4] = data;
1093: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
1.1.1.16 root 1094: if (!stepC) posC = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1095: break;
1096:
1097: case 5:
1098: SoundRegs[5] = data & 0x0f;
1099: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
1.1.1.16 root 1100: if (!stepC) posC = 1u<<BIT_SHIFT; // Assume output always 1 if 0 period (for Digi-sample)
1.1.1.12 root 1101: break;
1102:
1103: case 6:
1104: SoundRegs[6] = data & 0x1f;
1105: noiseStep = Ym2149_NoiseStepCompute ( SoundRegs[6] );
1106: if (!noiseStep)
1107: {
1108: noisePos = 0;
1109: currentNoise = 0xffff;
1110: }
1111: break;
1112:
1113: case 7:
1114: SoundRegs[7] = data & 0x3f; /* ignore bits 6 and 7 */
1115: mixerTA = (data&(1<<0)) ? 0xffff : 0;
1116: mixerTB = (data&(1<<1)) ? 0xffff : 0;
1117: mixerTC = (data&(1<<2)) ? 0xffff : 0;
1118: mixerNA = (data&(1<<3)) ? 0xffff : 0;
1119: mixerNB = (data&(1<<4)) ? 0xffff : 0;
1120: mixerNC = (data&(1<<5)) ? 0xffff : 0;
1121: break;
1122:
1123: case 8:
1124: SoundRegs[8] = data & 0x1f;
1125: if ( data & 0x10 )
1126: {
1127: EnvMask3Voices |= YM_MASK_A; /* env ON */
1128: Vol3Voices &= ~YM_MASK_A; /* fixed vol OFF */
1129: }
1130: else
1131: {
1132: EnvMask3Voices &= ~YM_MASK_A; /* env OFF */
1133: Vol3Voices &= ~YM_MASK_A; /* clear previous vol */
1134: Vol3Voices |= YmVolume4to5[ SoundRegs[8] ]; /* fixed vol ON */
1135: }
1136: break;
1.1.1.14 root 1137:
1.1.1.12 root 1138: case 9:
1139: SoundRegs[9] = data & 0x1f;
1140: if ( data & 0x10 )
1141: {
1142: EnvMask3Voices |= YM_MASK_B; /* env ON */
1143: Vol3Voices &= ~YM_MASK_B; /* fixed vol OFF */
1144: }
1145: else
1146: {
1147: EnvMask3Voices &= ~YM_MASK_B; /* env OFF */
1148: Vol3Voices &= ~YM_MASK_B; /* clear previous vol */
1149: Vol3Voices |= ( YmVolume4to5[ SoundRegs[9] ] ) << 5; /* fixed vol ON */
1150: }
1151: break;
1.1.1.14 root 1152:
1.1.1.12 root 1153: case 10:
1154: SoundRegs[10] = data & 0x1f;
1155: if ( data & 0x10 )
1156: {
1157: EnvMask3Voices |= YM_MASK_C; /* env ON */
1158: Vol3Voices &= ~YM_MASK_C; /* fixed vol OFF */
1159: }
1160: else
1161: {
1162: EnvMask3Voices &= ~YM_MASK_C; /* env OFF */
1163: Vol3Voices &= ~YM_MASK_C; /* clear previous vol */
1164: Vol3Voices |= ( YmVolume4to5[ SoundRegs[10] ] ) << 10; /* fixed vol ON */
1165: }
1166: break;
1167:
1168: case 11:
1169: SoundRegs[11] = data;
1170: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
1171: break;
1172:
1173: case 12:
1174: SoundRegs[12] = data;
1175: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
1176: break;
1177:
1178: case 13:
1179: SoundRegs[13] = data & 0xf;
1180: envPos = 0; /* when writing to EnvShape, we must reset the EnvPos */
1181: envShape = SoundRegs[13];
1.1.1.14 root 1182: bEnvelopeFreqFlag = true; /* used for YmFormat saving */
1.1.1.12 root 1183: break;
1184:
1185: }
1186: }
1187:
1188:
1189:
1190: /*-----------------------------------------------------------------------*/
1191: /**
1192: * Init random generator, sound tables and envelopes
1193: * (called only once when Hatari starts)
1194: */
1195: void Sound_Init(void)
1196: {
1197: /* Build volume/env tables, ... */
1198: Ym2149_Init();
1.1.1.14 root 1199:
1.1.1.11 root 1200: Sound_Reset();
1.1.1.7 root 1201: }
1202:
1203:
1204: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1205: /**
1.1.1.12 root 1206: * Reset the sound emulation (called from Reset_ST() in reset.c)
1.1.1.11 root 1207: */
1.1.1.7 root 1208: void Sound_Reset(void)
1209: {
1.1.1.11 root 1210: /* Lock audio system before accessing variables which are used by the
1211: * callback function, too! */
1212: Audio_Lock();
1.1.1.9 root 1213:
1.1.1.11 root 1214: /* Clear sound mixing buffer: */
1.1.1.12 root 1215: memset(MixBuffer, 0, sizeof(MixBuffer));
1.1.1.7 root 1216:
1.1.1.11 root 1217: /* Clear cycle counts, buffer index and register '13' flags */
1218: Cycles_SetCounter(CYCLES_COUNTER_SOUND, 0);
1.1.1.14 root 1219: bEnvelopeFreqFlag = false;
1220:
1.1.1.11 root 1221: CompleteSndBufIdx = 0;
1222: /* We do not start with 0 here to fake some initial samples: */
1223: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
1224: ActiveSndBufIdx = nGeneratedSamples % MIXBUFFER_SIZE;
1.1.1.16 root 1225: SamplesPerFrame = SAMPLES_PER_FRAME;
1226: CurrentSamplesNb = 0;
1227: ActiveSndBufIdxAvi = ActiveSndBufIdx;
1.1.1.15 root 1228: //fprintf ( stderr , "Sound_Reset SoundBufferSize %d SAMPLES_PER_FRAME %d nGeneratedSamples %d , ActiveSndBufIdx %d\n" ,
1229: // SoundBufferSize , SAMPLES_PER_FRAME, nGeneratedSamples , ActiveSndBufIdx );
1.1.1.7 root 1230:
1.1.1.12 root 1231: Ym2149_Reset();
1.1.1.9 root 1232:
1.1.1.11 root 1233: Audio_Unlock();
1.1.1.7 root 1234: }
1235:
1236:
1237: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1238: /**
1239: * Reset the sound buffer index variables.
1.1.1.16 root 1240: * Very important : this function should only be called by setting
1241: * Sound_BufferIndexNeedReset=true ; sound buffer index should be reset
1242: * only after the sound for the whole VBL was updated (CurrentSamplesNb returns to 0)
1243: * else it will alter the value of DMA Frame Count ($ff8909/0b/0d) and
1244: * could cause crashes in some programs.
1.1.1.11 root 1245: */
1.1.1.9 root 1246: void Sound_ResetBufferIndex(void)
1.1.1.7 root 1247: {
1.1.1.11 root 1248: Audio_Lock();
1249: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
1250: ActiveSndBufIdx = (CompleteSndBufIdx + nGeneratedSamples) % MIXBUFFER_SIZE;
1.1.1.16 root 1251: SamplesPerFrame = SAMPLES_PER_FRAME;
1252: CurrentSamplesNb = 0;
1253: ActiveSndBufIdxAvi = ActiveSndBufIdx;
1.1.1.15 root 1254: //fprintf ( stderr , "Sound_ResetBufferIndex SoundBufferSize %d SAMPLES_PER_FRAME %d nGeneratedSamples %d , ActiveSndBufIdx %d\n" ,
1255: // SoundBufferSize , SAMPLES_PER_FRAME, nGeneratedSamples , ActiveSndBufIdx );
1.1.1.11 root 1256: Audio_Unlock();
1.1.1.7 root 1257: }
1258:
1259:
1260: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1261: /**
1262: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
1263: */
1.1.1.12 root 1264: void Sound_MemorySnapShot_Capture(bool bSave)
1.1.1.7 root 1265: {
1.1.1.11 root 1266: /* Save/Restore details */
1.1.1.12 root 1267: MemorySnapShot_Store(&stepA, sizeof(stepA));
1268: MemorySnapShot_Store(&stepB, sizeof(stepB));
1269: MemorySnapShot_Store(&stepC, sizeof(stepC));
1270: MemorySnapShot_Store(&posA, sizeof(posA));
1271: MemorySnapShot_Store(&posB, sizeof(posB));
1272: MemorySnapShot_Store(&posC, sizeof(posC));
1273:
1274: MemorySnapShot_Store(&mixerTA, sizeof(mixerTA));
1275: MemorySnapShot_Store(&mixerTB, sizeof(mixerTB));
1276: MemorySnapShot_Store(&mixerTC, sizeof(mixerTC));
1277: MemorySnapShot_Store(&mixerNA, sizeof(mixerNA));
1278: MemorySnapShot_Store(&mixerNB, sizeof(mixerNB));
1279: MemorySnapShot_Store(&mixerNC, sizeof(mixerNC));
1280:
1281: MemorySnapShot_Store(&noiseStep, sizeof(noiseStep));
1282: MemorySnapShot_Store(&noisePos, sizeof(noisePos));
1283: MemorySnapShot_Store(¤tNoise, sizeof(currentNoise));
1284: MemorySnapShot_Store(&RndRack, sizeof(RndRack));
1285:
1286: MemorySnapShot_Store(&envStep, sizeof(envStep));
1287: MemorySnapShot_Store(&envPos, sizeof(envPos));
1288: MemorySnapShot_Store(&envShape, sizeof(envShape));
1.1.1.14 root 1289:
1.1.1.12 root 1290: MemorySnapShot_Store(&EnvMask3Voices, sizeof(EnvMask3Voices));
1291: MemorySnapShot_Store(&Vol3Voices, sizeof(Vol3Voices));
1.1.1.14 root 1292:
1.1.1.12 root 1293: MemorySnapShot_Store(SoundRegs, sizeof(SoundRegs));
1294:
1.1.1.14 root 1295: // MemorySnapShot_Store(&YmVolumeMixing, sizeof(YmVolumeMixing));
1296: // MemorySnapShot_Store(&UseLowPassFilter, sizeof(UseLowPassFilter));
1.1.1.7 root 1297: }
1298:
1299:
1300: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1301: /**
1302: * Find how many samples to generate and store in 'nSamplesToGenerate'
1303: * Also update sound cycles counter to store how many we actually did
1304: * so generates set amount each frame.
1.1.1.16 root 1305: * If FillFrame is true, this means we reach the end of the VBL and me must
1306: * add as many samples as necessary to get a total of SamplesPerFrame
1307: * for this VBL.
1.1.1.11 root 1308: */
1.1.1.16 root 1309: static int Sound_SetSamplesPassed(bool FillFrame)
1.1 root 1310: {
1.1.1.11 root 1311: int nSoundCycles;
1.1.1.16 root 1312: int SamplesToGenerate; /* How many samples are needed for this time-frame */
1313:
1314: nSoundCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.11 root 1315:
1.1.1.16 root 1316: /* example : 160256 cycles per VBL, 44Khz = 882 samples per VBL at 50 Hz */
1317: /* 882/160256 samples per cpu clock cycle */
1.1.1.11 root 1318:
1.1.1.16 root 1319: /* Total number of samples that we should have at this point of the VBL */
1320: SamplesToGenerate = nSoundCycles * SamplesPerFrame
1321: / ClocksTimings_GetCyclesPerVBL ( ConfigureParams.System.nMachineType , nScreenRefreshRate );
1.1.1.11 root 1322:
1.1.1.16 root 1323: //if (SamplesToGenerate > SamplesPerFrame )
1324: //fprintf ( stderr , "over run %d %d\n" , SamplesPerFrame , SamplesToGenerate );
1.1.1.11 root 1325:
1.1.1.16 root 1326: if (SamplesToGenerate > SamplesPerFrame)
1327: SamplesToGenerate = SamplesPerFrame;
1328:
1329: SamplesToGenerate -= CurrentSamplesNb; /* don't count samples that were already generated up to now */
1330: if ( SamplesToGenerate < 0 )
1331: SamplesToGenerate = 0;
1332:
1333:
1334: /* If we're called from the VBL interrupt (FillFrame==true), we must ensure we have */
1335: /* an exact total of SamplesPerFrame samples during a full VBL (we take into account */
1336: /* the samples that were already generated during this VBL) */
1337: if ( FillFrame )
1338: {
1339: SamplesToGenerate = SamplesPerFrame - CurrentSamplesNb; /* how many samples are missing to reach SamplesPerFrame */
1340: if ( SamplesToGenerate < 0 )
1341: SamplesToGenerate = 0;
1342: }
1.1.1.11 root 1343:
1.1.1.16 root 1344: /* Check we don't fill the sound's ring buffer before it's played by Audio_Callback() */
1345: /* This should never happen, except if the system suffers major slowdown due to other */
1346: /* processes or if we run in fast forward mode. */
1347: /* In the case of slowdown, we set Sound_BufferIndexNeedReset to "resync" the working */
1348: /* buffer's index ActiveSndBufIdx with the system buffer's index CompleteSndBufIdx. */
1349: /* In the case of fast forward, we do nothing here, Sound_BufferIndexNeedReset will be */
1350: /* set when the user exits fast forward mode. */
1351: if ( ( SamplesToGenerate > MIXBUFFER_SIZE - nGeneratedSamples ) && ( ConfigureParams.System.bFastForward == false )
1352: && ( ConfigureParams.Sound.bEnableSound == true ) )
1.1.1.11 root 1353: {
1.1.1.16 root 1354: Log_Printf ( LOG_WARN , "Your system is too slow, some sound samples were not correctly emulated\n" );
1355: Sound_BufferIndexNeedReset = true;
1.1.1.11 root 1356: }
1.1.1.16 root 1357:
1358: //fprintf ( stderr , "vbl %d hbl %d samp_gen %d / %d frac %lx\n" , nVBLs , nHBL , SamplesToGenerate , SamplesPerFrame , (long int)SamplesPerFrame_unrounded );
1359:
1360: return SamplesToGenerate;
1.1 root 1361: }
1362:
1.1.1.5 root 1363:
1.1.1.2 root 1364: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1365: /**
1366: * Generate samples for all channels during this time-frame
1367: */
1.1.1.16 root 1368: static void Sound_GenerateSamples(int SamplesToGenerate)
1.1 root 1369: {
1.1.1.12 root 1370: int i;
1371: int idx;
1.1.1.14 root 1372:
1.1.1.16 root 1373: if (SamplesToGenerate <= 0)
1.1.1.12 root 1374: return;
1.1.1.14 root 1375:
1.1.1.15 root 1376: if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
1.1.1.11 root 1377: {
1.1.1.16 root 1378: for (i = 0; i < SamplesToGenerate; i++)
1.1.1.15 root 1379: {
1380: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.17 root 1381: MixBuffer[idx][0] = MixBuffer[idx][1] = Subsonic_IIR_HPF_Left( YM2149_NextSample() );
1.1.1.15 root 1382: }
1383: /* If Falcon emulation, crossbar does the job */
1.1.1.16 root 1384: Crossbar_GenerateSamples(ActiveSndBufIdx, SamplesToGenerate);
1.1.1.11 root 1385: }
1.1.1.15 root 1386: else if (ConfigureParams.System.nMachineType != MACHINE_ST)
1387: {
1.1.1.16 root 1388: for (i = 0; i < SamplesToGenerate; i++)
1.1.1.15 root 1389: {
1390: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.18 root 1391: MixBuffer[idx][0] = MixBuffer[idx][1] = YM2149_NextSample();
1.1.1.15 root 1392: }
1.1.1.17 root 1393: /* If Ste or TT emulation, DmaSnd does mixing and filtering */
1.1.1.16 root 1394: DmaSnd_GenerateSamples(ActiveSndBufIdx, SamplesToGenerate);
1.1.1.15 root 1395: }
1396: else if (ConfigureParams.System.nMachineType == MACHINE_ST)
1397: {
1.1.1.16 root 1398: for (i = 0; i < SamplesToGenerate; i++)
1.1.1.15 root 1399: {
1400: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
1.1.1.17 root 1401: MixBuffer[idx][0] = MixBuffer[idx][1] = Subsonic_IIR_HPF_Left( YM2149_NextSample() );
1.1.1.15 root 1402: }
1403: }
1.1.1.12 root 1404:
1.1.1.16 root 1405: ActiveSndBufIdx = (ActiveSndBufIdx + SamplesToGenerate) % MIXBUFFER_SIZE;
1406: nGeneratedSamples += SamplesToGenerate;
1407: CurrentSamplesNb += SamplesToGenerate; /* number of samples generated for current VBL */
1.1 root 1408: }
1409:
1.1.1.5 root 1410:
1.1.1.2 root 1411: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1412: /**
1413: * This is called to built samples up until this clock cycle
1.1.1.16 root 1414: * Sound_Update can be called several times during a VBL ; we must ensure
1415: * that we generate exactly SamplesPerFrame samples between 2 calls
1416: * to Sound_Update_VBL.
1.1.1.11 root 1417: */
1.1.1.16 root 1418: void Sound_Update(bool FillFrame)
1.1 root 1419: {
1.1.1.11 root 1420: int OldSndBufIdx = ActiveSndBufIdx;
1.1.1.16 root 1421: int SamplesToGenerate;
1.1.1.5 root 1422:
1.1.1.11 root 1423: /* Make sure that we don't interfere with the audio callback function */
1424: Audio_Lock();
1.1.1.6 root 1425:
1.1.1.16 root 1426: /* Find how many samples to generate */
1427: SamplesToGenerate = Sound_SetSamplesPassed( FillFrame );
1428:
1.1.1.11 root 1429: /* And generate */
1.1.1.16 root 1430: Sound_GenerateSamples( SamplesToGenerate );
1.1 root 1431:
1.1.1.11 root 1432: /* Allow audio callback function to occur again */
1433: Audio_Unlock();
1.1.1.6 root 1434:
1.1.1.11 root 1435: /* Save to WAV file, if open */
1436: if (bRecordingWav)
1.1.1.16 root 1437: WAVFormat_Update(MixBuffer, OldSndBufIdx, SamplesToGenerate);
1.1 root 1438: }
1439:
1.1.1.5 root 1440:
1.1.1.2 root 1441: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1442: /**
1.1.1.16 root 1443: * On the end of each VBL, complete audio buffer to reach SamplesPerFrame samples.
1444: * As Sound_Update(false) could be called several times during the VBL, the audio
1445: * buffer might be already partially filled.
1446: * We must first complete the buffer using the same value of SamplesPerFrame
1447: * by calling Sound_Update(true) ; then we can compute a new value for
1448: * SamplesPerFrame that will be used for the next VBL to come.
1.1.1.11 root 1449: */
1.1.1.5 root 1450: void Sound_Update_VBL(void)
1.1 root 1451: {
1.1.1.16 root 1452: Sound_Update(true); /* generate as many samples as needed to fill this VBL */
1453: //fprintf ( stderr , "vbl done %d %d\n" , SamplesPerFrame , CurrentSamplesNb );
1.1.1.5 root 1454:
1.1.1.16 root 1455: CurrentSamplesNb = 0; /* VBL is complete, reset counter for next VBL */
1456:
1457: /*Compute a fractional equivalent of SamplesPerFrame for the next VBL, to avoid rounding propagation */
1458: SamplesPerFrame_unrounded += (yms64) ClocksTimings_GetSamplesPerVBL ( ConfigureParams.System.nMachineType ,
1459: nScreenRefreshRate , nAudioFrequency );
1460: SamplesPerFrame = SamplesPerFrame_unrounded >> 28; /* use integer part */
1461: SamplesPerFrame_unrounded &= 0x0fffffff; /* keep fractional part in the lower 28 bits */
1462:
1463: /* Reset sound buffer if needed (after pause, fast forward, slow system, ...) */
1464: if ( Sound_BufferIndexNeedReset )
1465: {
1466: Sound_ResetBufferIndex ();
1467: Sound_BufferIndexNeedReset = false;
1468: }
1469:
1470: /* Record AVI audio frame is necessary */
1.1.1.15 root 1471: if ( bRecordingAvi )
1472: {
1.1.1.16 root 1473: int Len;
1.1.1.15 root 1474:
1.1.1.16 root 1475: Len = ActiveSndBufIdx - ActiveSndBufIdxAvi; /* number of generated samples for this frame */
1476: if ( Len < 0 )
1477: Len += MIXBUFFER_SIZE; /* end of ring buffer was reached */
1.1.1.15 root 1478:
1.1.1.16 root 1479: Avi_RecordAudioStream ( MixBuffer , ActiveSndBufIdxAvi , Len );
1.1.1.15 root 1480: }
1481:
1.1.1.16 root 1482: ActiveSndBufIdxAvi = ActiveSndBufIdx; /* save new position for next AVI audio frame */
1483:
1.1.1.11 root 1484: /* Clear write to register '13', used for YM file saving */
1.1.1.14 root 1485: bEnvelopeFreqFlag = false;
1.1 root 1486: }
1487:
1488:
1.1.1.2 root 1489: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1490: /**
1491: * Start recording sound, as .YM or .WAV output
1492: */
1.1.1.12 root 1493: bool Sound_BeginRecording(char *pszCaptureFileName)
1.1 root 1494: {
1.1.1.12 root 1495: bool bRet;
1.1.1.7 root 1496:
1.1.1.11 root 1497: if (!pszCaptureFileName || strlen(pszCaptureFileName) <= 3)
1498: {
1499: Log_Printf(LOG_ERROR, "Illegal sound recording file name!\n");
1.1.1.14 root 1500: return false;
1.1.1.11 root 1501: }
1502:
1503: /* Did specify .YM or .WAV? If neither report error */
1504: if (File_DoesFileExtensionMatch(pszCaptureFileName,".ym"))
1505: bRet = YMFormat_BeginRecording(pszCaptureFileName);
1506: else if (File_DoesFileExtensionMatch(pszCaptureFileName,".wav"))
1507: bRet = WAVFormat_OpenFile(pszCaptureFileName);
1508: else
1509: {
1510: Log_AlertDlg(LOG_ERROR, "Unknown Sound Recording format.\n"
1511: "Please specify a .YM or .WAV output file.");
1.1.1.14 root 1512: bRet = false;
1.1.1.11 root 1513: }
1514:
1515: return bRet;
1.1 root 1516: }
1517:
1.1.1.5 root 1518:
1.1.1.2 root 1519: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1520: /**
1521: * End sound recording
1522: */
1.1.1.7 root 1523: void Sound_EndRecording(void)
1.1 root 1524: {
1.1.1.11 root 1525: /* Stop sound recording and close files */
1526: if (bRecordingYM)
1527: YMFormat_EndRecording();
1528: if (bRecordingWav)
1529: WAVFormat_CloseFile();
1.1 root 1530: }
1531:
1.1.1.6 root 1532:
1.1.1.2 root 1533: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1534: /**
1535: * Are we recording sound data?
1536: */
1.1.1.12 root 1537: bool Sound_AreWeRecording(void)
1.1 root 1538: {
1.1.1.11 root 1539: return (bRecordingYM || bRecordingWav);
1.1 root 1540: }
1.1.1.12 root 1541:
1.1.1.16 root 1542:
1543: /*-----------------------------------------------------------------------*/
1544: /**
1545: * Rebuild volume conversion table
1546: */
1547: void Sound_SetYmVolumeMixing(void)
1548: {
1549: /* Build the volume conversion table */
1550: Ym2149_BuildVolumeTable();
1551: }
1552:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.