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