|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - sound.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: 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:
21: The new version of the sound core uses 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.12 root 23: - 5 bits volume table and 16*16*16 combinations of all volume are from Sc68 by Benjamin Gerard
24: - 4 bits to 5 bits volume interpolation from 16*16*16 to 32*32*32 from YM blep synthesis by Antti Lankila
25:
1.1 root 26: */
1.1.1.12 root 27:
28: /* 2008/05/05 [NP] Fix case where period is 0 for noise, sound or envelope. */
29: /* In that case, a real ST sounds as if period was in fact 1. */
30: /* (fix buggy sound replay in ESwat that set volume<0 and trigger */
31: /* a badly initialised envelope with envper=0). */
32: /* 2008/07/27 [NP] Better separation between accesses to the YM hardware registers */
33: /* and the sound rendering routines. Use Sound_WriteReg() to pass */
34: /* all writes to the sound rendering functions. This allows to */
35: /* have sound.c independant of psg.c (to ease replacement of */
36: /* sound.c by another rendering method). */
37: /* 2008/08/02 [NP] Initial convert of Ym2149Ex.cpp from C++ to C. */
38: /* Remove unused part of the code (StSound specific). */
39: /* 2008/08/09 [NP] Complete integration of StSound routines into sound.c */
40: /* Set EnvPer=3 if EnvPer<3 (ESwat buggy replay). */
41: /* 2008/08/13 [NP] StSound was generating samples in the range 0-32767, instead */
42: /* of really signed samples between -32768 and 32767, which could */
43: /* give incorrect results in many case. */
44: /* 2008/09/06 [NP] Use sc68 volumes table for a more accurate mixing of the voices */
45: /* All volumes are converted to 5 bits and the table contains */
46: /* 32*32*32 values. Samples are signed and centered to get the */
47: /* biggest amplitude possible. */
48: /* Faster mixing routines for tone+volume+envelope (don't use */
49: /* StSound's version anymore, it gave problem with some GCC). */
50: /* 2008/09/17 [NP] Add ym_normalise_5bit_table to normalise the 32*32*32 table and */
51: /* to optionally center 16 bit signed sample. */
52: /* Possibility to mix volumes using a table measured on ST or a */
53: /* linear mean of the 3 channels' volume. */
54: /* Default mixing set to YM_LINEAR_MIXING. */
55: /* 2008/10/14 [NP] Full support for 5 bits volumes : envelopes are generated with */
56: /* 32 volumes per pattern as on a real YM-2149. Fixed volumes */
57: /* on 4 bits are converted to their 5 bits equivalent. This should */
58: /* give the maximum accuracy possible when computing volumes. */
59: /* New version of Ym2149_EnvStepCompute to handle 5 bits volumes. */
60: /* Function YM2149_EnvBuild to compute the 96 volumes that define */
61: /* a single envelope (32 initial volumes, then 64 repeated values).*/
62: /* 2008/10/26 [NP] Correctly save/restore all necessary variables in */
63: /* Sound_MemorySnapShot_Capture. */
64: /* 2008/11/23 [NP] Clean source, remove old sound core. */
65:
66:
67:
1.1.1.14 root 68: const char Sound_fileid[] = "Hatari sound.c : " __DATE__ " " __TIME__;
1.1.1.5 root 69:
70: #include <SDL_types.h>
1.1 root 71:
72: #include "main.h"
73: #include "audio.h"
1.1.1.10 root 74: #include "cycles.h"
1.1.1.15! root 75: #include "configuration.h"
1.1.1.9 root 76: #include "dmaSnd.h"
1.1.1.15! root 77: #include "crossbar.h"
1.1 root 78: #include "file.h"
1.1.1.15! root 79: #include "cycInt.h"
1.1.1.8 root 80: #include "log.h"
1.1 root 81: #include "memorySnapShot.h"
82: #include "psg.h"
83: #include "sound.h"
84: #include "video.h"
85: #include "wavFormat.h"
86: #include "ymFormat.h"
1.1.1.15! root 87: #include "avi_record.h"
1.1 root 88:
89:
90:
1.1.1.12 root 91: /*--------------------------------------------------------------*/
92: /* Definition of the possible envelopes shapes (using 5 bits) */
93: /*--------------------------------------------------------------*/
94:
95: #define ENV_GODOWN 0 /* 31 -> 0 */
96: #define ENV_GOUP 1 /* 0 -> 31 */
97: #define ENV_DOWN 2 /* 0 -> 0 */
98: #define ENV_UP 3 /* 31 -> 31 */
99:
100: /* To generate an envelope, we first use block 0, then we repeat blocks 1 and 2 */
101: static const int YmEnvDef[ 16 ][ 3 ] = {
102: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 0 \___ */
103: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 1 \___ */
104: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 2 \___ */
105: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 3 \___ */
106: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 4 /___ */
107: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 5 /___ */
108: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 6 /___ */
109: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* 7 /___ */
110: { ENV_GODOWN, ENV_GODOWN, ENV_GODOWN } , /* 8 \\\\ */
111: { ENV_GODOWN, ENV_DOWN, ENV_DOWN } , /* 9 \___ */
112: { ENV_GODOWN, ENV_GOUP, ENV_GODOWN } , /* A \/\/ */
113: { ENV_GODOWN, ENV_UP, ENV_UP } , /* B \--- */
114: { ENV_GOUP, ENV_GOUP, ENV_GOUP } , /* C //// */
115: { ENV_GOUP, ENV_UP, ENV_UP } , /* D /--- */
116: { ENV_GOUP, ENV_GODOWN, ENV_GOUP } , /* E /\/\ */
117: { ENV_GOUP, ENV_DOWN, ENV_DOWN } , /* F /___ */
118: };
119:
120:
121: /* Buffer to store the 16 envelopes built from YmEnvDef */
122: static ymu16 YmEnvWaves[ 16 ][ 32 * 3 ]; /* 16 envelopes with 3 blocks of 32 volumes */
1.1.1.3 root 123:
1.1 root 124:
1.1.1.12 root 125:
126: /*--------------------------------------------------------------*/
127: /* Definition of the volumes tables (using 5 bits) and of the */
128: /* mixing parameters for the 3 voices. */
129: /*--------------------------------------------------------------*/
130:
131: /* 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) */
132: /* Vol 0 should be 310 when measuread as a voltage, but we set it to 0 in order to have a volume=0 matching */
133: /* the 0 level of a 16 bits unsigned sample (no sound output) */
134: static const ymu16 ymout1c5bit[ 32 ] =
135: {
136: 0 /*310*/, 369, 438, 521, 619, 735, 874, 1039,
137: 1234, 1467, 1744, 2072, 2463, 2927, 3479, 4135,
138: 4914, 5841, 6942, 8250, 9806,11654,13851,16462,
139: 19565,23253,27636,32845,39037,46395,55141,65535
1.1 root 140: };
141:
1.1.1.12 root 142: /* Convert a constant 4 bits volume to the internal 5 bits value : */
143: /* volume5=volume4*2+1, except for volumes 0 and 1 which become 0 and 2, */
144: /* in order to map [0,15] into [0,31] (O must remain 0, and 15 must give 31) */
145: static const ymu16 YmVolume4to5[ 16 ] = { 0,2,5,7,9,11,13,15,17,19,21,23,25,27,29,31 };
1.1 root 146:
1.1.1.12 root 147: /* Table of unsigned 4 bit D/A output level for 3 channels as measured on a real ST */
148: static ymu16 volumetable_original[ 16 * 16 * 16 ] =
149: #include "ym2149_fixed_vol.h"
1.1.1.5 root 150:
1.1.1.12 root 151: /* Corresponding table interpolated to 5 bit D/A output level (16 bits unsigned) */
152: static ymu16 ymout5_u16[ 32 * 32 * 32 ];
153:
154: /* Same table, after conversion to signed results (same pointer, with different type) */
155: static yms16 *ymout5 = (yms16 *)ymout5_u16;
156:
157:
158:
159: /*--------------------------------------------------------------*/
160: /* Other constants / macros */
161: /*--------------------------------------------------------------*/
162:
163: /* Number of generated samples per frame (eg. 44Khz=882) */
1.1.1.14 root 164: #define SAMPLES_PER_FRAME ((nAudioFrequency+35)/nScreenRefreshRate)
1.1.1.12 root 165:
166: /* Current sound replay freq (usually 44100 Hz) */
1.1.1.14 root 167: #define YM_REPLAY_FREQ nAudioFrequency
1.1.1.12 root 168:
169: /* YM-2149 clock on Atari ST is 2 MHz */
1.1.1.15! root 170: #define YM_ATARI_CLOCK (CPU_FREQ / 4)
1.1.1.12 root 171:
172:
173: /* Merge/read the 3 volumes in a single integer (5 bits per volume) */
174: #define YM_MERGE_VOICE(C,B,A) ( (C)<<10 | (B)<<5 | A )
175: #define YM_MASK_1VOICE 0x1f
176: #define YM_MASK_A 0x1f
177: #define YM_MASK_B (0x1f<<5)
178: #define YM_MASK_C (0x1f<<10)
179:
180:
181: /* Constants for YM2149_Normalise_5bit_Table */
182: #define YM_OUTPUT_LEVEL 0x7fff /* amplitude of the final signal (0..65535 if centered, 0..32767 if not) */
1.1.1.14 root 183: #define YM_OUTPUT_CENTERED false
1.1.1.12 root 184:
185:
186:
187: /*--------------------------------------------------------------*/
188: /* Variables for the DC adjuster / Low Pass Filter */
189: /*--------------------------------------------------------------*/
190: #define DC_ADJUST_BUFFERLEN 512 /* must be a power of 2 */
191:
192: static ymsample dc_buffer[DC_ADJUST_BUFFERLEN];
193: static int dc_pos;
194: static int dc_sum;
195: static ymsample m_lowPassFilter[2];
196:
197:
198:
199: /*--------------------------------------------------------------*/
200: /* Variables for the YM2149 emulator (need to be saved and */
201: /* restored in memory snapshots) */
202: /*--------------------------------------------------------------*/
203:
204: static ymu32 stepA , stepB , stepC;
205: static ymu32 posA , posB , posC;
206: static ymu32 mixerTA , mixerTB , mixerTC;
207: static ymu32 mixerNA , mixerNB , mixerNC;
208:
209: static ymu32 noiseStep;
210: static ymu32 noisePos;
211: static ymu32 currentNoise;
212: static ymu32 RndRack; /* current random seed */
213:
214: static ymu32 envStep;
215: static ymu32 envPos;
216: static int envShape;
217:
218: static ymu16 EnvMask3Voices = 0; /* mask is 0x1f for voices having an active envelope */
219: static ymu16 Vol3Voices = 0; /* volume 0-0x1f for voices having a constant volume */
220: /* volume is set to 0 if voice has an envelope in EnvMask3Voices */
221:
222:
223: /* Global variables that can be changed/read from other parts of Hatari */
224: Uint8 SoundRegs[ 14 ];
225:
226: int YmVolumeMixing = YM_LINEAR_MIXING;
1.1.1.14 root 227: bool UseLowPassFilter = false;
1.1.1.12 root 228:
229: bool bEnvelopeFreqFlag; /* Cleared each frame for YM saving */
230:
231: Sint16 MixBuffer[MIXBUFFER_SIZE][2];
232: int nGeneratedSamples; /* Generated samples since audio buffer update */
233: int nSamplesToGenerate; /* How many samples are needed for this time-frame */
234: static int ActiveSndBufIdx; /* Current working index into above mix buffer */
235:
236:
237:
238: /*--------------------------------------------------------------*/
239: /* Local functions prototypes */
240: /*--------------------------------------------------------------*/
241:
242: static void DcAdjuster_Reset (void);
243: static void DcAdjuster_AddSample (ymsample sample);
244: static ymsample DcAdjuster_GetDcLevel (void);
245: static void LowPassFilter_Reset (void);
246: static ymsample LowPassFilter (ymsample in);
247:
248: static int volumetable_get (int i, int j, int k);
249: static void volumetable_set (ymu16 *volumetable, int i, int j, int k, int val);
250: static int volumetable_interpolate (int y1, int y2);
251: static void interpolate_volumetable (ymu16 *out);
252:
253: static void YM2149_BuildLinearVolumeTable(ymu16 *out);
254: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter);
255:
256: static void YM2149_EnvBuild (void);
257: static void Ym2149_Init (void);
258: static void Ym2149_Reset (void);
259:
260: static ymu32 YM2149_RndCompute (void);
261: static ymu32 Ym2149_ToneStepCompute (ymu8 rHigh , ymu8 rLow);
262: static ymu32 Ym2149_NoiseStepCompute (ymu8 rNoise);
263: static ymu32 Ym2149_EnvStepCompute (ymu8 rHigh , ymu8 rLow);
264: static ymsample YM2149_NextSample (void);
265:
266: static void Sound_SetSamplesPassed (void);
267: static void Sound_GenerateSamples (void);
268:
269:
270:
271: /*--------------------------------------------------------------*/
272: /* DC Adjuster / Low Pass Filter routines. */
273: /*--------------------------------------------------------------*/
274:
275: static void DcAdjuster_Reset(void)
276: {
277: int i;
1.1.1.14 root 278:
1.1.1.12 root 279: for (i=0 ; i<DC_ADJUST_BUFFERLEN ; i++)
280: dc_buffer[i] = 0;
281:
282: dc_pos = 0;
283: dc_sum = 0;
284: }
285:
286:
287: static void DcAdjuster_AddSample(ymsample sample)
1.1 root 288: {
1.1.1.12 root 289: dc_sum -= dc_buffer[dc_pos];
290: dc_sum += sample;
1.1 root 291:
1.1.1.12 root 292: dc_buffer[dc_pos] = sample;
293: dc_pos = (dc_pos+1)&(DC_ADJUST_BUFFERLEN-1);
294: }
295:
296:
297: static ymsample DcAdjuster_GetDcLevel(void)
298: {
299: return dc_sum / DC_ADJUST_BUFFERLEN;
300: }
301:
302:
303: static void LowPassFilter_Reset(void)
304: {
305: m_lowPassFilter[0] = 0;
306: m_lowPassFilter[1] = 0;
307: }
308:
309:
310: static ymsample LowPassFilter(ymsample in)
311: {
312: ymsample out;
313:
314: out = (m_lowPassFilter[0]>>2) + (m_lowPassFilter[1]>>1) + (in>>2);
315: m_lowPassFilter[0] = m_lowPassFilter[1];
316: m_lowPassFilter[1] = in;
317: return out;
318: }
319:
320:
321:
322: /*--------------------------------------------------------------*/
323: /* Build the volume conversion table used to simulate the */
324: /* behaviour of DAC used with the YM2149 in the atari ST. */
325: /* The final 32*32*32 table is built using a 16*16*16 table */
326: /* of all possible fixed volume combinations on a ST. */
327: /*--------------------------------------------------------------*/
328:
329: static int volumetable_get(int i, int j, int k)
330: {
331: /* access at boundary finds the last value instead of the first */
332: if (i == 16)
333: i = 15;
334: if (j == 16)
335: j = 15;
336: if (k == 16)
337: k = 15;
1.1.1.14 root 338:
1.1.1.12 root 339: return volumetable_original[i + 16 * j + 16 * 16 * k];
340: }
341:
342: static void volumetable_set(ymu16 *volumetable, int i, int j, int k, int val)
343: {
344: volumetable[i + 32 * j + 32 * 32 * k] = val;
345: }
346:
347: /* the table is exponential in nature. These weighing factors approximate
348: * that the value in-between needs to be closer to the lower value in y2 */
349: static int volumetable_interpolate(int y1, int y2)
350: {
351: int erpolate;
352: erpolate = (y1 * 4 + y2 * 6) / 10u;
353: if (erpolate > 65535)
1.1.1.11 root 354: {
1.1.1.12 root 355: // fprintf ( stderr , "sature>:%d %d %d\n",erpolate,y1,y2 );
356: erpolate = 65535;
1.1.1.11 root 357: }
1.1.1.12 root 358: if (erpolate < 0)
359: {
360: // fprintf ( stderr , "sature<:%d %d %d\n",erpolate,y1,y2 );
361: erpolate = 0;
362: }
363: return erpolate;
364: }
1.1.1.11 root 365:
1.1.1.12 root 366: static void interpolate_volumetable(ymu16 *out)
367: {
368: int i, j, k;
369: int i1, i2;
370:
371: /* we are doing 4-dimensional interpolation here. For each
372: * known measurement point, we must find 8 new values. These values occur
373: * as follows:
374: *
375: * - one at the exact same position
376: * - one half-way in i direction
377: * - one half-way in j direction
378: * - one half-way in k direction
379: * - one half-way in i+j direction
380: * - one half-way in i+k direction
381: * - one half-way in j+k direction
382: * - one half-way in i+j+k direction
383: *
384: * The algorithm currently is very simplistic. Probably more points should be
385: * weighted in the multicomponented directions, for instance i+j+k should be
386: * an average of all surrounding data points. This probably doesn't matter much,
387: * though. This is because the only way to reach those locations is to modulate
388: * more than one voice with the envelope, and this is rare.
389: */
390:
391: for (i = 0; i < 16; i++)
1.1.1.11 root 392: {
1.1.1.12 root 393: for (j = 0; j < 16; j++)
394: {
395: for (k = 0; k < 16; k++)
396: {
397: i1 = volumetable_get(i, j, k);
398: /* copy value unchanged to new position */
399: volumetable_set(out,i*2, j*2, k*2, i1);
1.1.1.14 root 400:
1.1.1.12 root 401: /* interpolate in i direction */
402: i2 = volumetable_get(i + 1, j, k);
403: volumetable_set(out,i*2 + 1, j*2, k*2, volumetable_interpolate(i1, i2));
1.1.1.14 root 404:
1.1.1.12 root 405: /* interpolate in j direction */
406: i2 = volumetable_get(i, j+1, k);
407: volumetable_set(out,i*2, j*2 + 1, k*2, volumetable_interpolate(i1, i2));
1.1.1.14 root 408:
1.1.1.12 root 409: /* interpolate in k direction */
410: i2 = volumetable_get(i, j, k+1);
411: volumetable_set(out,i*2, j*2, k*2+1, volumetable_interpolate(i1, i2));
412:
413: /* interpolate in i + j direction */
414: i2 = volumetable_get(i + 1, j + 1, k);
415: volumetable_set(out,i*2 + 1, j*2 + 1, k*2, volumetable_interpolate(i1, i2));
1.1.1.14 root 416:
1.1.1.12 root 417: /* interpolate in i + k direction */
418: i2 = volumetable_get(i + 1, j, k + 1);
419: volumetable_set(out,i*2 + 1, j*2, k*2 + 1, volumetable_interpolate(i1, i2));
1.1.1.14 root 420:
1.1.1.12 root 421: /* interpolate in j + k direction */
422: i2 = volumetable_get(i, j + 1, k + 1);
423: volumetable_set(out,i*2, j*2 + 1, k*2 + 1, volumetable_interpolate(i1, i2));
424:
425: /* interpolate in i + j + k direction */
426: i2 = volumetable_get(i + 1, j + 1, k + 1);
427: volumetable_set(out,i*2 + 1, j*2 + 1, k*2 + 1, volumetable_interpolate(i1, i2));
428: }
429: }
1.1.1.11 root 430: }
1.1 root 431: }
432:
1.1.1.5 root 433:
1.1.1.12 root 434:
435:
1.1.1.2 root 436: /*-----------------------------------------------------------------------*/
1.1.1.11 root 437: /**
1.1.1.12 root 438: * Build a linear version of the conversion table.
439: * We use the mean of the 3 volumes converted to 16 bit values
440: * (each value of ymout1c5bit is in [0,65535])
1.1.1.11 root 441: */
1.1.1.12 root 442:
443: static void YM2149_BuildLinearVolumeTable(ymu16 *out)
1.1 root 444: {
1.1.1.12 root 445: int i, j, k;
446: int res;
447:
448: for (i = 0; i < 32; i++)
449: for (j = 0; j < 32; j++)
450: for (k = 0; k < 32; k++)
451: {
452: res = ( ymout1c5bit[ i ] + ymout1c5bit[ j ] + ymout1c5bit[ k ] ) / 3;
453: volumetable_set ( out, i, j, k, res );
454: }
455: }
456:
457:
458:
1.1 root 459:
1.1.1.12 root 460: /*-----------------------------------------------------------------------*/
461: /**
462: * Normalise and optionally center the volume table used to
463: * convert the 3 volumes to a final signed 16 bit sample.
464: * This allows to adapt the amplitude/volume of the samples and
465: * to convert unsigned values to signed values.
466: * - in_5bit contains 32*32*32 unsigned values in the range
467: * [0,65535].
468: * - out_5bit will contain signed values
469: * Possible values are :
470: * Level=65535 and DoCenter=TRUE -> [-32768,32767]
1.1.1.14 root 471: * Level=32767 and DoCenter=false -> [0,32767]
1.1.1.12 root 472: */
473:
474: static void YM2149_Normalise_5bit_Table(ymu16 *in_5bit , yms16 *out_5bit, unsigned int Level, bool DoCenter)
475: {
476: if ( Level )
1.1.1.11 root 477: {
1.1.1.14 root 478: int h;
1.1.1.12 root 479: int Max = in_5bit[0x7fff];
480: int Center = Level>>1;
1.1.1.14 root 481: //fprintf ( stderr , "level %d max %d center %d\n" , Level, Max, Center );
482:
1.1.1.12 root 483: /* Change the amplitude of the signal to 'level' : [0,max] -> [0,level] */
484: /* Then optionally center the signal around Level/2 */
485: /* This means we go from sthg like [0,65535] to [-32768, 32767] if Level=65535 and DoCenter=TRUE */
486: for (h=0; h<32*32*32; h++)
487: {
488: int tmp = in_5bit[h], res;
489: res = tmp * Level / Max;
1.1.1.14 root 490:
1.1.1.12 root 491: if ( DoCenter )
492: res -= Center;
493:
494: out_5bit[h] = res;
1.1.1.14 root 495: //fprintf ( stderr , "h %d in %d out %d\n" , h , tmp , res );
1.1.1.12 root 496: }
1.1.1.11 root 497: }
1.1 root 498: }
499:
1.1.1.5 root 500:
1.1.1.12 root 501:
502:
1.1.1.2 root 503: /*-----------------------------------------------------------------------*/
1.1.1.11 root 504: /**
1.1.1.12 root 505: * Precompute all 16 possible envelopes.
506: * Each envelope is made of 3 blocks of 32 volumes.
1.1.1.11 root 507: */
1.1.1.12 root 508:
509: static void YM2149_EnvBuild ( void )
1.1 root 510: {
1.1.1.12 root 511: int env;
512: int block;
513: int vol=0 , inc=0;
514: int i;
1.1 root 515:
1.1.1.12 root 516:
517: for ( env=0 ; env<16 ; env++ ) /* 16 possible envelopes */
518: for ( block=0 ; block<3 ; block++ ) /* 3 blocks to define an envelope */
519: {
1.1.1.14 root 520: switch ( YmEnvDef[ env ][ block ] )
521: {
1.1.1.12 root 522: case ENV_GODOWN : vol=31 ; inc=-1 ; break;
523: case ENV_GOUP : vol=0 ; inc=1 ; break;
524: case ENV_DOWN : vol=0 ; inc=0 ; break;
525: case ENV_UP : vol=31 ; inc=0 ; break;
1.1.1.14 root 526: }
527:
1.1.1.12 root 528: for ( i=0 ; i<32 ; i++ ) /* 32 volumes per block */
529: {
530: YmEnvWaves[ env ][ block*32 + i ] = YM_MERGE_VOICE ( vol , vol , vol );
531: vol += inc;
532: }
533: }
534: }
535:
536:
537:
538: /*-----------------------------------------------------------------------*/
539: /**
540: * Init some internal tables for faster results (env, volume)
541: * and reset the internal states.
542: */
543:
544: static void Ym2149_Init(void)
545: {
546: /* Build the 16 envelope shapes */
547: YM2149_EnvBuild();
548:
549: /* Depending on the volume mixing method, we use a table based on real measures */
550: /* or a table based on a linear volume mixing. */
551: if ( YmVolumeMixing == YM_TABLE_MIXING )
552: interpolate_volumetable(ymout5_u16); /* expand the 16*16*16 values in volumetable_original to 32*32*32 */
553: else
554: YM2149_BuildLinearVolumeTable(ymout5_u16); /* combine the 32 possible volumes */
555:
556: /* Normalise/center the values (convert from u16 to s16) */
557: YM2149_Normalise_5bit_Table ( ymout5_u16 , ymout5 , YM_OUTPUT_LEVEL , YM_OUTPUT_CENTERED );
558:
559: /* Reset YM2149 internal states */
560: Ym2149_Reset();
561: }
562:
563:
564:
565: /*-----------------------------------------------------------------------*/
566: /**
567: * Reset all ym registers as well as the internal varaibles
568: */
569:
570: static void Ym2149_Reset(void)
571: {
572: int i;
1.1.1.14 root 573:
1.1.1.12 root 574: for ( i=0 ; i<14 ; i++ )
575: Sound_WriteReg ( i , 0 );
576:
577: Sound_WriteReg ( 7 , 0xff );
578:
579: currentNoise = 0xffff;
1.1.1.14 root 580:
1.1.1.12 root 581: RndRack = 1;
1.1.1.14 root 582:
1.1.1.12 root 583: envShape = 0;
584: envPos = 0;
585:
586: DcAdjuster_Reset ();
587: LowPassFilter_Reset ();
588: }
589:
590:
591:
592: /*-----------------------------------------------------------------------*/
593: /**
594: * Returns a pseudo random value, used to generate white noise.
595: */
596:
597: static ymu32 YM2149_RndCompute(void)
598: {
599: ymu32 bit;
1.1.1.14 root 600:
1.1.1.12 root 601: bit = (RndRack&1) ^ ((RndRack>>2)&1);
602: RndRack = (RndRack>>1) | (bit<<16);
603: return (bit ? 0 : 0xffff);
604: }
605:
606:
607:
608: /*-----------------------------------------------------------------------*/
609: /**
610: * Compute steps for tone, noise and env, based on the input
611: * period.
612: */
613:
614: static ymu32 Ym2149_ToneStepCompute(ymu8 rHigh , ymu8 rLow)
615: {
616: int per;
1.1.1.14 root 617: yms64 step;
1.1.1.12 root 618:
619: per = rHigh&15;
620: per = (per<<8)+rLow;
1.1.1.14 root 621: if (per <= 5)
1.1.1.12 root 622: return 0;
623:
1.1.1.14 root 624: step = YM_ATARI_CLOCK;
1.1.1.12 root 625: step <<= (15+16-3);
626: step /= (per * YM_REPLAY_FREQ);
627:
628: return step;
629: }
630:
631:
632: static ymu32 Ym2149_NoiseStepCompute(ymu8 rNoise)
633: {
634: int per;
1.1.1.14 root 635: yms64 step;
1.1.1.12 root 636:
637: per = (rNoise&0x1f);
638: if (per<3)
639: return 0;
640:
1.1.1.14 root 641: step = YM_ATARI_CLOCK;
1.1.1.12 root 642: step <<= (16-1-3);
643: step /= (per * YM_REPLAY_FREQ);
644:
645: return step;
1.1 root 646: }
647:
1.1.1.5 root 648:
1.1.1.2 root 649: /*-----------------------------------------------------------------------*/
1.1.1.11 root 650: /**
1.1.1.12 root 651: * Compute envelope's step. The envelope is made of different patterns
652: * of 32 volumes. In each pattern, the volume is changed at frequency
653: * Fe = MasterClock / ( 8 * EnvPer ).
654: * In our case, we use a lower replay freq ; between 2 consecutive calls
655: * to envelope's generation, the internal counter will advance 'step'
656: * units, where step = MasterClock / ( 8 * EnvPer * YM_REPLAY_FREQ )
657: * As 'step' requires floating point to be stored, we use left shifting
658: * to multiply 'step' by a fixed amount. All operations are made with
659: * shifted values ; to get the final value, we must right shift the
660: * result. We use '<<24', which gives 8 bits for the integer part, and
661: * the equivalent of 24 bits for the fractional part.
662: * Since we're using large numbers, we temporarily use 64 bits integer
663: * to avoid overflow and keep largest precision possible.
1.1.1.11 root 664: */
1.1.1.12 root 665:
666: static ymu32 Ym2149_EnvStepCompute(ymu8 rHigh , ymu8 rLow)
1.1 root 667: {
1.1.1.12 root 668: yms64 per;
1.1.1.14 root 669: yms64 step;
1.1 root 670:
1.1.1.12 root 671: per = rHigh;
672: per = (per<<8)+rLow;
673:
1.1.1.14 root 674: step = YM_ATARI_CLOCK;
1.1.1.12 root 675: step <<= 24;
676: if ( per > 0 )
677: step /= (8 * per * YM_REPLAY_FREQ); /* 0x5ab < step < 0x5ab3f46 at 44.1 kHz */
678: else
679: step /= (8 * 1/2 * YM_REPLAY_FREQ); /* result for Per=0 is half the result for Per=1 */
680:
681: return step;
682: }
683:
684:
685:
686: /*-----------------------------------------------------------------------*/
687: /**
688: * Main function : compute the value of the next sample.
689: * Mixes all 3 voices with tone+noise+env and apply low pass
690: * filter if needed.
691: */
692:
693: static ymsample YM2149_NextSample(void)
694: {
695: ymsample sample;
696: int bt;
697: ymu32 bn;
698: ymu16 Env3Voices;
699: ymu16 Tone3Voices;
700:
701:
702: /* Noise value : 0 or 0xffff */
703: if ( noisePos&0xffff0000 )
704: {
705: currentNoise ^= YM2149_RndCompute();
706: noisePos &= 0xffff;
707: }
708: bn = currentNoise; /* 0 or 0xffff */
709:
710: /* Get the 5 bits volume corresponding to the current envelope's position */
711: Env3Voices = YmEnvWaves[ envShape ][ envPos>>24 ]; /* integer part of envPos is in bits 24-31 */
712: Env3Voices &= EnvMask3Voices; /* only keep volumes for voices using envelope */
713:
714: //fprintf ( stderr , "env %x %x %x\n" , Env3Voices , envStep , envPos );
715:
716: /* Tone3Voices will contain the output state of each voice : 0 or 0x1f */
717: bt = ((((yms32)posA)>>31) | mixerTA) & (bn | mixerNA); /* 0 or 0xffff */
718: Tone3Voices = bt & YM_MASK_1VOICE; /* 0 or 0x1f */
719: bt = ((((yms32)posB)>>31) | mixerTB) & (bn | mixerNB);
720: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 5;
721: bt = ((((yms32)posC)>>31) | mixerTC) & (bn | mixerNC);
722: Tone3Voices |= ( bt & YM_MASK_1VOICE ) << 10;
723:
724: /* Combine fixed volumes and envelope volumes and keep the resulting */
725: /* volumes depending on the output state of each voice (0 or 0x1f) */
726: Tone3Voices &= ( Env3Voices | Vol3Voices );
727:
728: /* D/A conversion of the 3 volumes into a sample using a precomputed conversion table */
729: sample = ymout5[ Tone3Voices ]; /* 16 bits signed value */
730:
731:
732: /* Increment positions */
733: posA += stepA;
734: posB += stepB;
735: posC += stepC;
736: noisePos += noiseStep;
1.1.1.14 root 737:
1.1.1.12 root 738: envPos += envStep;
739: if ( envPos >= (3*32) << 24 ) /* blocks 0, 1 and 2 were used (envPos 0 to 95) */
740: envPos -= (2*32) << 24; /* replay/loop blocks 1 and 2 (envPos 32 to 95) */
741:
1.1.1.14 root 742: DcAdjuster_AddSample(sample); /* Calculate DC level */
743: sample = sample - DcAdjuster_GetDcLevel(); /* normalize sound level */
1.1.1.12 root 744:
745: /* Apply low pass filter ? */
746: if ( UseLowPassFilter )
1.1.1.11 root 747: {
1.1.1.14 root 748: sample = LowPassFilter(sample);
1.1.1.11 root 749: }
1.1.1.12 root 750:
751: return sample;
1.1 root 752: }
753:
754:
1.1.1.12 root 755:
1.1.1.2 root 756: /*-----------------------------------------------------------------------*/
1.1.1.11 root 757: /**
1.1.1.12 root 758: * Update internal variables (steps, volume masks, ...) each
759: * time an YM register is changed.
1.1.1.11 root 760: */
761:
1.1.1.12 root 762: void Sound_WriteReg( int reg , Uint8 data )
1.1.1.7 root 763: {
1.1.1.12 root 764: switch (reg)
765: {
766: case 0:
767: SoundRegs[0] = data;
768: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
769: if (!stepA) posA = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
770: break;
771:
772: case 1:
773: SoundRegs[1] = data & 0x0f;
774: stepA = Ym2149_ToneStepCompute ( SoundRegs[1] , SoundRegs[0] );
775: if (!stepA) posA = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
776: break;
777:
778: case 2:
779: SoundRegs[2] = data;
780: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
781: if (!stepB) posB = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
782: break;
1.1.1.7 root 783:
1.1.1.12 root 784: case 3:
785: SoundRegs[3] = data & 0x0f;
786: stepB = Ym2149_ToneStepCompute ( SoundRegs[3] , SoundRegs[2] );
787: if (!stepB) posB = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
788: break;
789:
790: case 4:
791: SoundRegs[4] = data;
792: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
793: if (!stepC) posC = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
794: break;
795:
796: case 5:
797: SoundRegs[5] = data & 0x0f;
798: stepC = Ym2149_ToneStepCompute ( SoundRegs[5] , SoundRegs[4] );
799: if (!stepC) posC = 1u<<31; // Assume output always 1 if 0 period (for Digi-sample)
800: break;
801:
802: case 6:
803: SoundRegs[6] = data & 0x1f;
804: noiseStep = Ym2149_NoiseStepCompute ( SoundRegs[6] );
805: if (!noiseStep)
806: {
807: noisePos = 0;
808: currentNoise = 0xffff;
809: }
810: break;
811:
812: case 7:
813: SoundRegs[7] = data & 0x3f; /* ignore bits 6 and 7 */
814: mixerTA = (data&(1<<0)) ? 0xffff : 0;
815: mixerTB = (data&(1<<1)) ? 0xffff : 0;
816: mixerTC = (data&(1<<2)) ? 0xffff : 0;
817: mixerNA = (data&(1<<3)) ? 0xffff : 0;
818: mixerNB = (data&(1<<4)) ? 0xffff : 0;
819: mixerNC = (data&(1<<5)) ? 0xffff : 0;
820: break;
821:
822: case 8:
823: SoundRegs[8] = data & 0x1f;
824: if ( data & 0x10 )
825: {
826: EnvMask3Voices |= YM_MASK_A; /* env ON */
827: Vol3Voices &= ~YM_MASK_A; /* fixed vol OFF */
828: }
829: else
830: {
831: EnvMask3Voices &= ~YM_MASK_A; /* env OFF */
832: Vol3Voices &= ~YM_MASK_A; /* clear previous vol */
833: Vol3Voices |= YmVolume4to5[ SoundRegs[8] ]; /* fixed vol ON */
834: }
835: break;
1.1.1.14 root 836:
1.1.1.12 root 837: case 9:
838: SoundRegs[9] = data & 0x1f;
839: if ( data & 0x10 )
840: {
841: EnvMask3Voices |= YM_MASK_B; /* env ON */
842: Vol3Voices &= ~YM_MASK_B; /* fixed vol OFF */
843: }
844: else
845: {
846: EnvMask3Voices &= ~YM_MASK_B; /* env OFF */
847: Vol3Voices &= ~YM_MASK_B; /* clear previous vol */
848: Vol3Voices |= ( YmVolume4to5[ SoundRegs[9] ] ) << 5; /* fixed vol ON */
849: }
850: break;
1.1.1.14 root 851:
1.1.1.12 root 852: case 10:
853: SoundRegs[10] = data & 0x1f;
854: if ( data & 0x10 )
855: {
856: EnvMask3Voices |= YM_MASK_C; /* env ON */
857: Vol3Voices &= ~YM_MASK_C; /* fixed vol OFF */
858: }
859: else
860: {
861: EnvMask3Voices &= ~YM_MASK_C; /* env OFF */
862: Vol3Voices &= ~YM_MASK_C; /* clear previous vol */
863: Vol3Voices |= ( YmVolume4to5[ SoundRegs[10] ] ) << 10; /* fixed vol ON */
864: }
865: break;
866:
867: case 11:
868: SoundRegs[11] = data;
869: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
870: break;
871:
872: case 12:
873: SoundRegs[12] = data;
874: envStep = Ym2149_EnvStepCompute ( SoundRegs[12] , SoundRegs[11] );
875: break;
876:
877: case 13:
878: SoundRegs[13] = data & 0xf;
879: envPos = 0; /* when writing to EnvShape, we must reset the EnvPos */
880: envShape = SoundRegs[13];
1.1.1.14 root 881: bEnvelopeFreqFlag = true; /* used for YmFormat saving */
1.1.1.12 root 882: break;
883:
884: }
885: }
886:
887:
888:
889: /*-----------------------------------------------------------------------*/
890: /**
891: * Init random generator, sound tables and envelopes
892: * (called only once when Hatari starts)
893: */
894: void Sound_Init(void)
895: {
896: /* Build volume/env tables, ... */
897: Ym2149_Init();
1.1.1.14 root 898:
1.1.1.11 root 899: Sound_Reset();
1.1.1.7 root 900: }
901:
902:
903: /*-----------------------------------------------------------------------*/
1.1.1.11 root 904: /**
1.1.1.12 root 905: * Reset the sound emulation (called from Reset_ST() in reset.c)
1.1.1.11 root 906: */
1.1.1.7 root 907: void Sound_Reset(void)
908: {
1.1.1.11 root 909: /* Lock audio system before accessing variables which are used by the
910: * callback function, too! */
911: Audio_Lock();
1.1.1.9 root 912:
1.1.1.11 root 913: /* Clear sound mixing buffer: */
1.1.1.12 root 914: memset(MixBuffer, 0, sizeof(MixBuffer));
1.1.1.7 root 915:
1.1.1.11 root 916: /* Clear cycle counts, buffer index and register '13' flags */
917: Cycles_SetCounter(CYCLES_COUNTER_SOUND, 0);
1.1.1.14 root 918: bEnvelopeFreqFlag = false;
919:
1.1.1.11 root 920: CompleteSndBufIdx = 0;
921: /* We do not start with 0 here to fake some initial samples: */
922: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
923: ActiveSndBufIdx = nGeneratedSamples % MIXBUFFER_SIZE;
1.1.1.15! root 924: //fprintf ( stderr , "Sound_Reset SoundBufferSize %d SAMPLES_PER_FRAME %d nGeneratedSamples %d , ActiveSndBufIdx %d\n" ,
! 925: // SoundBufferSize , SAMPLES_PER_FRAME, nGeneratedSamples , ActiveSndBufIdx );
1.1.1.7 root 926:
1.1.1.12 root 927: Ym2149_Reset();
1.1.1.9 root 928:
1.1.1.11 root 929: Audio_Unlock();
1.1.1.7 root 930: }
931:
932:
933: /*-----------------------------------------------------------------------*/
1.1.1.11 root 934: /**
935: * Reset the sound buffer index variables.
936: */
1.1.1.9 root 937: void Sound_ResetBufferIndex(void)
1.1.1.7 root 938: {
1.1.1.11 root 939: Audio_Lock();
940: nGeneratedSamples = SoundBufferSize + SAMPLES_PER_FRAME;
941: ActiveSndBufIdx = (CompleteSndBufIdx + nGeneratedSamples) % MIXBUFFER_SIZE;
1.1.1.15! root 942: //fprintf ( stderr , "Sound_ResetBufferIndex SoundBufferSize %d SAMPLES_PER_FRAME %d nGeneratedSamples %d , ActiveSndBufIdx %d\n" ,
! 943: // SoundBufferSize , SAMPLES_PER_FRAME, nGeneratedSamples , ActiveSndBufIdx );
1.1.1.11 root 944: Audio_Unlock();
1.1.1.7 root 945: }
946:
947:
948: /*-----------------------------------------------------------------------*/
1.1.1.11 root 949: /**
950: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
951: */
1.1.1.12 root 952: void Sound_MemorySnapShot_Capture(bool bSave)
1.1.1.7 root 953: {
1.1.1.11 root 954: /* Save/Restore details */
1.1.1.12 root 955: MemorySnapShot_Store(&stepA, sizeof(stepA));
956: MemorySnapShot_Store(&stepB, sizeof(stepB));
957: MemorySnapShot_Store(&stepC, sizeof(stepC));
958: MemorySnapShot_Store(&posA, sizeof(posA));
959: MemorySnapShot_Store(&posB, sizeof(posB));
960: MemorySnapShot_Store(&posC, sizeof(posC));
961:
962: MemorySnapShot_Store(&mixerTA, sizeof(mixerTA));
963: MemorySnapShot_Store(&mixerTB, sizeof(mixerTB));
964: MemorySnapShot_Store(&mixerTC, sizeof(mixerTC));
965: MemorySnapShot_Store(&mixerNA, sizeof(mixerNA));
966: MemorySnapShot_Store(&mixerNB, sizeof(mixerNB));
967: MemorySnapShot_Store(&mixerNC, sizeof(mixerNC));
968:
969: MemorySnapShot_Store(&noiseStep, sizeof(noiseStep));
970: MemorySnapShot_Store(&noisePos, sizeof(noisePos));
971: MemorySnapShot_Store(¤tNoise, sizeof(currentNoise));
972: MemorySnapShot_Store(&RndRack, sizeof(RndRack));
973:
974: MemorySnapShot_Store(&envStep, sizeof(envStep));
975: MemorySnapShot_Store(&envPos, sizeof(envPos));
976: MemorySnapShot_Store(&envShape, sizeof(envShape));
1.1.1.14 root 977:
1.1.1.12 root 978: MemorySnapShot_Store(&EnvMask3Voices, sizeof(EnvMask3Voices));
979: MemorySnapShot_Store(&Vol3Voices, sizeof(Vol3Voices));
1.1.1.14 root 980:
1.1.1.12 root 981: MemorySnapShot_Store(SoundRegs, sizeof(SoundRegs));
982:
1.1.1.14 root 983: // MemorySnapShot_Store(&YmVolumeMixing, sizeof(YmVolumeMixing));
984: // MemorySnapShot_Store(&UseLowPassFilter, sizeof(UseLowPassFilter));
1.1.1.7 root 985: }
986:
987:
988: /*-----------------------------------------------------------------------*/
1.1.1.11 root 989: /**
990: * Find how many samples to generate and store in 'nSamplesToGenerate'
991: * Also update sound cycles counter to store how many we actually did
992: * so generates set amount each frame.
993: */
1.1.1.7 root 994: static void Sound_SetSamplesPassed(void)
1.1 root 995: {
1.1.1.11 root 996: int nSampleCycles;
997: int nSamplesPerFrame;
998: int nSoundCycles;
999:
1000: nSoundCycles = Cycles_GetCounter(CYCLES_COUNTER_SOUND);
1001:
1002: /* 160256 cycles per VBL, 44Khz = 882 samples per VBL */
1003: /* 882/160256 samples per clock cycle */
1004: nSamplesPerFrame = SAMPLES_PER_FRAME;
1005:
1006: nSamplesToGenerate = nSoundCycles * nSamplesPerFrame / CYCLES_PER_FRAME;
1007: if (nSamplesToGenerate > nSamplesPerFrame)
1008: nSamplesToGenerate = nSamplesPerFrame;
1009:
1010: nSampleCycles = nSamplesToGenerate * CYCLES_PER_FRAME / nSamplesPerFrame;
1011: nSoundCycles -= nSampleCycles;
1012: Cycles_SetCounter(CYCLES_COUNTER_SOUND, nSoundCycles);
1013:
1014: if (nSamplesToGenerate > MIXBUFFER_SIZE - nGeneratedSamples)
1015: {
1016: nSamplesToGenerate = MIXBUFFER_SIZE - nGeneratedSamples;
1017: if (nSamplesToGenerate < 0)
1018: nSamplesToGenerate = 0;
1019: }
1.1 root 1020: }
1021:
1.1.1.5 root 1022:
1.1.1.2 root 1023: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1024: /**
1025: * Generate samples for all channels during this time-frame
1026: */
1.1.1.5 root 1027: static void Sound_GenerateSamples(void)
1.1 root 1028: {
1.1.1.12 root 1029: int i;
1030: int idx;
1.1.1.14 root 1031:
1.1.1.12 root 1032: if (nSamplesToGenerate <= 0)
1033: return;
1.1.1.14 root 1034:
1.1.1.15! root 1035: if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
1.1.1.11 root 1036: {
1.1.1.15! root 1037: for (i = 0; i < nSamplesToGenerate; i++)
! 1038: {
! 1039: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
! 1040: MixBuffer[idx][0] = MixBuffer[idx][1] = YM2149_NextSample();
! 1041: }
! 1042: /* If Falcon emulation, crossbar does the job */
! 1043: Crossbar_GenerateSamples(ActiveSndBufIdx, nSamplesToGenerate);
1.1.1.11 root 1044: }
1.1.1.15! root 1045: else if (ConfigureParams.System.nMachineType != MACHINE_ST)
! 1046: {
! 1047: for (i = 0; i < nSamplesToGenerate; i++)
! 1048: {
! 1049: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
! 1050: MixBuffer[idx][0] = MixBuffer[idx][1] = (YM2149_NextSample() >> 1);
! 1051: }
! 1052: /* If Ste or TT emulation, DmaSnd does the job */
! 1053: DmaSnd_GenerateSamples(ActiveSndBufIdx, nSamplesToGenerate);
! 1054: }
! 1055: else if (ConfigureParams.System.nMachineType == MACHINE_ST)
! 1056: {
! 1057: for (i = 0; i < nSamplesToGenerate; i++)
! 1058: {
! 1059: idx = (ActiveSndBufIdx + i) % MIXBUFFER_SIZE;
! 1060: MixBuffer[idx][0] = MixBuffer[idx][1] = YM2149_NextSample();
! 1061: }
! 1062: /* If ST emulation, DmaSnd doesn't do the job
! 1063: DmaSnd_GenerateSamples(ActiveSndBufIdx, nSamplesToGenerate); */
! 1064: }
1.1.1.12 root 1065:
1066: ActiveSndBufIdx = (ActiveSndBufIdx + nSamplesToGenerate) % MIXBUFFER_SIZE;
1067: nGeneratedSamples += nSamplesToGenerate;
1.1 root 1068: }
1069:
1.1.1.5 root 1070:
1.1.1.2 root 1071: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1072: /**
1073: * This is called to built samples up until this clock cycle
1074: */
1.1.1.5 root 1075: void Sound_Update(void)
1.1 root 1076: {
1.1.1.11 root 1077: int OldSndBufIdx = ActiveSndBufIdx;
1.1.1.5 root 1078:
1.1.1.11 root 1079: /* Make sure that we don't interfere with the audio callback function */
1080: Audio_Lock();
1.1.1.6 root 1081:
1.1.1.11 root 1082: /* Find how many to generate */
1083: Sound_SetSamplesPassed();
1084: /* And generate */
1085: Sound_GenerateSamples();
1.1 root 1086:
1.1.1.11 root 1087: /* Allow audio callback function to occur again */
1088: Audio_Unlock();
1.1.1.6 root 1089:
1.1.1.11 root 1090: /* Save to WAV file, if open */
1091: if (bRecordingWav)
1092: WAVFormat_Update(MixBuffer, OldSndBufIdx, nSamplesToGenerate);
1.1 root 1093: }
1094:
1.1.1.5 root 1095:
1.1.1.2 root 1096: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1097: /**
1098: * On each VBL (50fps) complete samples.
1099: */
1.1.1.5 root 1100: void Sound_Update_VBL(void)
1.1 root 1101: {
1.1.1.11 root 1102: Sound_Update();
1.1.1.5 root 1103:
1.1.1.15! root 1104: /* Record audio frame is necessary */
! 1105: if ( bRecordingAvi )
! 1106: {
! 1107: int SamplePerVbl = nAudioFrequency / nScreenRefreshRate;
! 1108: int PrevIndex;
! 1109:
! 1110: PrevIndex = ActiveSndBufIdx - SamplePerVbl;
! 1111: if ( PrevIndex < 0 )
! 1112: PrevIndex += MIXBUFFER_SIZE;
! 1113:
! 1114: Avi_RecordAudioStream ( MixBuffer , PrevIndex , SamplePerVbl );
! 1115: }
! 1116:
1.1.1.11 root 1117: /* Clear write to register '13', used for YM file saving */
1.1.1.14 root 1118: bEnvelopeFreqFlag = false;
1.1 root 1119: }
1120:
1121:
1.1.1.2 root 1122: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1123: /**
1124: * Start recording sound, as .YM or .WAV output
1125: */
1.1.1.12 root 1126: bool Sound_BeginRecording(char *pszCaptureFileName)
1.1 root 1127: {
1.1.1.12 root 1128: bool bRet;
1.1.1.7 root 1129:
1.1.1.11 root 1130: if (!pszCaptureFileName || strlen(pszCaptureFileName) <= 3)
1131: {
1132: Log_Printf(LOG_ERROR, "Illegal sound recording file name!\n");
1.1.1.14 root 1133: return false;
1.1.1.11 root 1134: }
1135:
1136: /* Did specify .YM or .WAV? If neither report error */
1137: if (File_DoesFileExtensionMatch(pszCaptureFileName,".ym"))
1138: bRet = YMFormat_BeginRecording(pszCaptureFileName);
1139: else if (File_DoesFileExtensionMatch(pszCaptureFileName,".wav"))
1140: bRet = WAVFormat_OpenFile(pszCaptureFileName);
1141: else
1142: {
1143: Log_AlertDlg(LOG_ERROR, "Unknown Sound Recording format.\n"
1144: "Please specify a .YM or .WAV output file.");
1.1.1.14 root 1145: bRet = false;
1.1.1.11 root 1146: }
1147:
1148: return bRet;
1.1 root 1149: }
1150:
1.1.1.5 root 1151:
1.1.1.2 root 1152: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1153: /**
1154: * End sound recording
1155: */
1.1.1.7 root 1156: void Sound_EndRecording(void)
1.1 root 1157: {
1.1.1.11 root 1158: /* Stop sound recording and close files */
1159: if (bRecordingYM)
1160: YMFormat_EndRecording();
1161: if (bRecordingWav)
1162: WAVFormat_CloseFile();
1.1 root 1163: }
1164:
1.1.1.6 root 1165:
1.1.1.2 root 1166: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1167: /**
1168: * Are we recording sound data?
1169: */
1.1.1.12 root 1170: bool Sound_AreWeRecording(void)
1.1 root 1171: {
1.1.1.11 root 1172: return (bRecordingYM || bRecordingWav);
1.1 root 1173: }
1.1.1.12 root 1174:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.