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