Annotation of hatari/src/sound.c, revision 1.1.1.15

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.