Annotation of generator/main/gensound.c, revision 1.1.1.4

1.1       root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
                      2: 
1.1.1.2   root        3: #include <stdlib.h>
1.1       root        4: 
                      5: #include "generator.h"
                      6: #include "gensound.h"
1.1.1.2   root        7: #include "gensoundp.h"
1.1       root        8: #include "vdp.h"
                      9: #include "ui.h"
1.1.1.2   root       10: #include "sn76496.h"
1.1       root       11: 
                     12: #ifdef JFM
                     13: #  include "jfm.h"
                     14: #else
                     15: #  include "support.h"
                     16: #  include "fm.h"
                     17: #endif
                     18: 
                     19: /*** variables externed ***/
                     20: 
1.1.1.2   root       21: int sound_debug = 0;            /* debug mode */
                     22: int sound_feedback = 0;         /* -1, running out of sound
                     23:                                    +0, lots of sound, do something */
                     24: unsigned int sound_minfields = 5;       /* min fields to try to buffer */
                     25: unsigned int sound_maxfields = 10;      /* max fields before blocking */
1.1.1.3   root       26: unsigned int sound_speed = SOUND_SAMPLERATE;    /* sample rate */
1.1.1.2   root       27: unsigned int sound_sampsperfield;       /* samples per field */
                     28: unsigned int sound_threshold;   /* samples in buffer aiming for */
1.1       root       29: uint8 sound_regs1[256];
                     30: uint8 sound_regs2[256];
                     31: uint8 sound_address1 = 0;
                     32: uint8 sound_address2 = 0;
                     33: uint8 sound_keys[8];
1.1.1.3   root       34: int sound_logsample = 0;        /* sample to log or -1 if none */
                     35: unsigned int sound_on = 1;      /* sound enabled */
                     36: unsigned int sound_psg = 1;     /* psg enabled */
                     37: unsigned int sound_fm = 1;      /* fm enabled */
1.1.1.4 ! root       38: unsigned int sound_filter = 50; /* low-pass filter percentage (0-100) */
1.1       root       39: 
1.1.1.2   root       40: /* pal is lowest framerate */
                     41: uint16 sound_soundbuf[2][SOUND_MAXRATE / 50];
1.1       root       42: 
                     43: /*** forward references ***/
                     44: 
1.1.1.3   root       45: static void sound_process(void);
                     46: static void sound_writetolog(unsigned char c);
                     47: 
1.1       root       48: /*** file scoped variables ***/
                     49: 
                     50: static int sound_active = 0;
1.1.1.3   root       51: static uint8 *sound_logdata;    /* log data */
                     52: static unsigned int sound_logdata_size; /* sound_logdata size */
                     53: static unsigned int sound_logdata_p;    /* current log data offset */
                     54: static unsigned int sound_fieldhassamples;      /* flag if field has samples */
1.1       root       55: 
                     56: #ifdef JFM
1.1.1.2   root       57: static t_jfm_ctx *sound_ctx;
1.1       root       58: #endif
                     59: 
                     60: /*** sound_init - initialise this sub-unit ***/
                     61: 
                     62: int sound_init(void)
                     63: {
                     64:   int ret;
                     65: 
1.1.1.2   root       66:   /* The sound_minfields parameter specifies how many fields worth of sound we
                     67:      should try and keep around (a display field is 1/50th or 1/60th of a
                     68:      second) - generator works by trying to keep sound_minfields number of
                     69:      fields worth of sound around, and drops plotting frames to keep up on slow
                     70:      machines */
                     71: 
                     72:   sound_sampsperfield = sound_speed / vdp_framerate;
                     73:   sound_threshold = sound_sampsperfield * sound_minfields;
                     74: 
1.1       root       75:   ret = sound_start();
                     76:   if (ret)
                     77:     return ret;
                     78: #ifdef JFM
1.1.1.2   root       79:   if ((sound_ctx = jfm_init(0, 2612, vdp_clock / 7, sound_speed,
                     80:                             NULL, NULL)) == NULL) {
                     81: #else
                     82:   if (YM2612Init(1, vdp_clock / 7, sound_speed, NULL, NULL)) {
                     83: #endif
                     84:     LOG_VERBOSE(("YM2612 failed init"));
                     85:     sound_stop();
                     86:     return 1;
                     87:   }
                     88:   if (SN76496Init(0, vdp_clock / 15, 0, sound_speed)) {
                     89:     LOG_VERBOSE(("SN76496 failed init"));
                     90:     sound_stop();
                     91: #ifdef JFM
                     92:     jfm_final(sound_ctx);
1.1       root       93: #else
1.1.1.2   root       94:     YM2612Shutdown();
1.1       root       95: #endif
                     96:     return 1;
                     97:   }
1.1.1.3   root       98:   if (sound_logdata)
                     99:     free(sound_logdata);
                    100:   sound_logdata_size = 8192;
                    101:   sound_logdata = malloc(sound_logdata_size);
                    102:   if (!sound_logdata)
                    103:     ui_err("out of memory");
1.1       root      104:   LOG_VERBOSE(("YM2612 Initialised @ sample rate %d", sound_speed));
                    105:   return 0;
                    106: }
                    107: 
                    108: /*** sound_final - finalise this sub-unit ***/
                    109: 
                    110: void sound_final(void)
                    111: {
                    112:   sound_stop();
                    113: #ifdef JFM
                    114:   jfm_final(sound_ctx);
                    115: #else
                    116:   YM2612Shutdown();
                    117: #endif
                    118: }
                    119: 
1.1.1.2   root      120: /*** sound_start - start sound ***/
1.1       root      121: 
                    122: int sound_start(void)
                    123: {
                    124:   if (sound_active)
                    125:     sound_stop();
1.1.1.2   root      126:   LOG_VERBOSE(("Starting sound..."));
1.1.1.4 ! root      127:   if (soundp_start() != 0) {
1.1.1.2   root      128:     LOG_VERBOSE(("Failed to start sound hardware"));
                    129:     return -1;
1.1       root      130:   }
                    131:   sound_active = 1;
1.1.1.2   root      132:   LOG_VERBOSE(("Started sound."));
1.1       root      133:   return 0;
                    134: }
1.1.1.2   root      135: 
1.1       root      136: /*** sound_stop - stop sound ***/
                    137: 
                    138: void sound_stop(void)
                    139: {
                    140:   if (!sound_active)
                    141:     return;
                    142:   LOG_VERBOSE(("Stopping sound..."));
1.1.1.2   root      143:   soundp_stop();
1.1       root      144:   sound_active = 0;
                    145:   LOG_VERBOSE(("Stopped sound."));
                    146: }
1.1.1.2   root      147: 
1.1       root      148: /*** sound_reset - reset sound sub-unit ***/
                    149: 
                    150: int sound_reset(void)
                    151: {
                    152:   sound_final();
                    153:   return sound_init();
                    154: }
                    155: 
1.1.1.3   root      156: /*** sound_startfield - start of frame ***/
                    157: 
                    158: void sound_startfield(void)
                    159: {
                    160:   sound_logdata_p = 0;
                    161:   if (gen_musiclog == musiclog_gnm) {
                    162:     sound_writetolog(0);
                    163:     sound_writetolog((vdp_totlines >> 8) & 0xff);
                    164:     sound_writetolog(vdp_totlines & 0xff);
                    165:     sound_fieldhassamples = 0;
                    166:   }
                    167: }
1.1       root      168: /*** sound_endfield - end frame and output sound ***/
                    169: 
                    170: void sound_endfield(void)
                    171: {
1.1.1.2   root      172:   int pending;
1.1.1.3   root      173:   uint8 *p, *o;
                    174: 
                    175:   if (gen_musiclog) {
                    176:     if (gen_musiclog == musiclog_gym) {
                    177:       /* GYM format ends a field with a 0 byte */
                    178:       sound_writetolog(0);
                    179:     } else {
                    180:       /* GNM format requires sifting through the data */
                    181:       if (!sound_fieldhassamples) {
                    182:         /* we're only removing data, so we're going to write to the buffer
                    183:            we're reading from */
                    184:         o = sound_logdata + 3;
                    185:         for (p = sound_logdata + 3;
                    186:              p < (sound_logdata + sound_logdata_p); p++) {
                    187:           if ((*p & 0xF0) != 0x00 || *p == 4)
                    188:             ui_err("assertion of no samples failed");
                    189:           switch (*p) {
                    190:           case 0:
                    191:             ui_err("field marker in middle of field data");
                    192:           case 1:
                    193:           case 2:
                    194:             /* FM data, copy 2 and two bytes to output */
                    195:             *o++ = *p++;
                    196:             *o++ = *p++;
                    197:             *o++ = *p;
                    198:             break;
                    199:           case 3:
                    200:             /* PSG data, copy 3 and one byte to output */
                    201:             *o++ = *p++;
                    202:             *o++ = *p;
                    203:             break;
                    204:           case 5:
                    205:             /* these are the bytes we're trying to strip */
                    206:             /* do nothing */
                    207:             break;
                    208:           default:
                    209:             ui_err("invalid data in sound log buffer");
                    210:           }
                    211:         }
                    212:         /* update new end of buffer */
                    213:         sound_logdata_p = o - sound_logdata;
                    214:         sound_logdata[1] = 0; /* high byte number of samples */
                    215:         sound_logdata[2] = 0; /* low byte number of samples */
                    216:       }
                    217:     }
                    218:     /* write data */
                    219:     ui_musiclog(sound_logdata, sound_logdata_p);
                    220:     /* sound_startfield resets everything */
                    221:   }
                    222: 
                    223:   if (!sound_on) {
                    224:     /* sound is turned off - let generator continue */
                    225:     sound_feedback = 0;
                    226:     return;
                    227:   }
1.1.1.2   root      228: 
                    229:   /* work out feedback from sound system */
                    230: 
                    231:   if ((pending = soundp_samplesbuffered()) == -1)
                    232:     ui_err("Failed to read pending bytes in output sound buffer");
                    233:   if ((unsigned int)pending < sound_threshold)
1.1       root      234:     sound_feedback = -1;
                    235:   else
                    236:     sound_feedback = 0;
1.1.1.2   root      237: 
1.1       root      238:   if (sound_debug) {
1.1.1.2   root      239:     LOG_VERBOSE(("End of field - sound system says %d bytes buffered",
                    240:                  pending));
                    241:     LOG_VERBOSE(("Threshold %d, therefore feedback = %d ", sound_threshold,
                    242:                  sound_feedback));
1.1       root      243:   }
1.1.1.2   root      244:   soundp_output(sound_soundbuf[0], sound_soundbuf[1], sound_sampsperfield);
1.1       root      245: }
                    246: 
                    247: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/
                    248: 
                    249: uint8 sound_ym2612fetch(uint8 addr)
                    250: {
                    251: #ifdef JFM
                    252:   return jfm_read(sound_ctx, addr);
                    253: #else
                    254:   return YM2612Read(0, addr);
                    255: #endif
                    256: }
                    257: 
                    258: /*** sound_ym2612store - store a byte to the ym2612 chip ***/
                    259: 
                    260: void sound_ym2612store(uint8 addr, uint8 data)
                    261: {
                    262:   switch (addr) {
                    263:   case 0:
                    264:     sound_address1 = data;
                    265:     break;
                    266:   case 1:
                    267:     if (sound_address1 == 0x2a) {
1.1.1.3   root      268:       /* sample data */
1.1       root      269:       sound_keys[7] = 0;
1.1.1.3   root      270:       sound_logsample = data;
                    271:     } else {
                    272:       if (gen_musiclog != musiclog_off) {
                    273:         /* GYM and GNM */
                    274:         sound_writetolog(1);
                    275:         sound_writetolog(sound_address1);
                    276:         sound_writetolog(data);
                    277:       }
1.1       root      278:     }
1.1.1.3   root      279:     if (sound_address1 == 0x28 && (data & 3) != 3)
                    280:       sound_keys[data & 7] = data >> 4;
1.1       root      281:     if (sound_address1 == 0x2b)
                    282:       sound_keys[7] = data & 0x80 ? 0xf : 0;
                    283:     sound_regs1[sound_address1] = data;
                    284:     break;
                    285:   case 2:
1.1.1.3   root      286:     if (gen_musiclog != musiclog_off) {
                    287:       /* GYM and GNM */
                    288:       sound_writetolog(2);
                    289:       sound_writetolog(sound_address2);
                    290:       sound_writetolog(data);
                    291:     }
1.1       root      292:     sound_address2 = data;
                    293:     break;
                    294:   case 3:
                    295:     sound_regs2[sound_address2] = data;
                    296:     break;
                    297:   }
                    298: #ifdef JFM
                    299:   jfm_write(sound_ctx, addr, data);
                    300: #else
                    301:   YM2612Write(0, addr, data);
                    302: #endif
                    303: }
                    304: 
1.1.1.2   root      305: /*** sound_sn76496store - store a byte to the sn76496 chip ***/
                    306: 
                    307: void sound_sn76496store(uint8 data)
                    308: {
1.1.1.3   root      309:   if (gen_musiclog != musiclog_off) {
                    310:     /* GYM and GNM */
                    311:     sound_writetolog(3);
                    312:     sound_writetolog(data);
                    313:   }
1.1.1.2   root      314:   SN76496Write(0, data);
                    315: }
                    316: 
                    317: /*** sound_genreset - reset genesis sound ***/
                    318: 
                    319: void sound_genreset(void)
                    320: {
                    321: #ifdef JFM
                    322:   jfm_reset(sound_ctx);
                    323: #else
                    324:   YM2612ResetChip(0);
                    325: #endif
                    326: }
                    327: 
1.1.1.3   root      328: /*** sound_line - called at end of line ***/
                    329: 
                    330: void sound_line(void)
                    331: {
                    332:   if (gen_musiclog == musiclog_gnm) {
                    333:     /* GNM log */
                    334:     if (sound_logsample == -1) {
                    335:       sound_writetolog(5);
                    336:     } else {
                    337:       if ((sound_logsample & 0xF0) == 0) {
                    338:         sound_writetolog(4);
                    339:       }
                    340:       sound_writetolog(sound_logsample);
                    341:       sound_logsample = -1;
                    342:       /* mark the fact that we have encountered a sample this field */
                    343:       sound_fieldhassamples = 1;
                    344:     }
                    345:   }
                    346:   sound_process();
                    347: }
                    348: 
1.1.1.2   root      349: /*** sound_process - process sound ***/
                    350: 
1.1.1.3   root      351: static void sound_process(void)
1.1.1.2   root      352: {
                    353:   static sint16 *tbuf[2];
                    354:   int s1 = (sound_sampsperfield * (vdp_line)) / vdp_totlines;
                    355:   int s2 = (sound_sampsperfield * (vdp_line + 1)) / vdp_totlines;
                    356:   /* pal is lowest framerate */
                    357:   uint16 sn76496buf[SOUND_MAXRATE / 50];        /* far too much but who cares */
                    358:   unsigned int samples = s2 - s1;
                    359:   unsigned int i;
1.1.1.4 ! root      360:   static sint32 ll, rr;
        !           361:   uint32 factora = (0x10000 * sound_filter) / 100;
        !           362:   uint32 factorb = 0x10000 - factora;
1.1.1.2   root      363: 
                    364:   tbuf[0] = sound_soundbuf[0] + s1;
                    365:   tbuf[1] = sound_soundbuf[1] + s1;
                    366: 
                    367:   if (s2 > s1) {
1.1.1.3   root      368:     if (sound_fm)
1.1.1.2   root      369: #ifdef JFM
1.1.1.3   root      370:       jfm_update(sound_ctx, (void **)tbuf, samples1);
1.1.1.2   root      371: #else
1.1.1.3   root      372:       YM2612UpdateOne(0, tbuf, samples);
1.1.1.2   root      373: #endif
                    374: 
                    375:     /* SN76496 outputs sound in range -0x4000 to 0x3fff
                    376:        YM2612 ouputs sound in range -0x8000 to 0x7fff - therefore
                    377:        we take 3/4 of the YM2612 and add half the SN76496 */
1.1.1.3   root      378: 
1.1.1.4 ! root      379:     /* this uses a single-pole low-pass filter (6 dB/octave) curtesy of
        !           380:        Jon Watte <[email protected]> */
        !           381: 
1.1.1.3   root      382:     if (sound_fm && sound_psg) {
1.1.1.4 ! root      383:       SN76496Update(0, sn76496buf, samples);
1.1.1.3   root      384:       for (i = 0; i < samples; i++) {
1.1.1.4 ! root      385:         sint16 snsample = ((sint16)sn76496buf[i] - 0x4000) >> 1;
        !           386:         sint32 l = snsample + ((tbuf[0][i] * 3) >> 2); /* left channel */
        !           387:         sint32 r = snsample + ((tbuf[1][i] * 3) >> 2); /* right channel */
        !           388:         ll = (ll >> 16) * factora + (l * factorb);
        !           389:         rr = (rr >> 16) * factora + (r * factorb);
        !           390:         tbuf[0][i] = ll >> 16;
        !           391:         tbuf[1][i] = rr >> 16;
1.1.1.3   root      392:       }
                    393:     } else if (!sound_fm && !sound_psg) {
                    394:       /* no sound */
                    395:       memset(tbuf[0], 0, 2 * samples);
                    396:       memset(tbuf[1], 0, 2 * samples);
                    397:     } else if (sound_fm) {
                    398:       /* fm only */
                    399:       for (i = 0; i < samples; i++) {
                    400:         sint32 l = (tbuf[0][i] * 3) >> 2; /* left channel */
                    401:         sint32 r = (tbuf[1][i] * 3) >> 2; /* right channel */
1.1.1.4 ! root      402:         ll = (ll >> 16) * factora + (l * factorb);
        !           403:         rr = (rr >> 16) * factora + (r * factorb);
        !           404:         tbuf[0][i] = ll >> 16;
        !           405:         tbuf[1][i] = rr >> 16;
1.1.1.3   root      406:       }
                    407:     } else {
                    408:       /* psg only */
1.1.1.4 ! root      409:       SN76496Update(0, sn76496buf, samples);
1.1.1.3   root      410:       for (i = 0; i < samples; i++) {
1.1.1.4 ! root      411:         sint16 snsample = ((sint16)(sn76496buf[i] - 0x4000)) >> 1;
        !           412:         ll = (ll >> 16) * factora + (snsample * factorb);
        !           413:         rr = (rr >> 16) * factora + (snsample * factorb);
        !           414:         tbuf[0][i] = ll >> 16;
        !           415:         tbuf[1][i] = rr >> 16;
1.1.1.3   root      416:       }
1.1.1.2   root      417:     }
                    418:   }
                    419: }
1.1.1.3   root      420: 
                    421: /*** sound_writetolog - write to music log buffer ***/
                    422: 
                    423: static void sound_writetolog(unsigned char c)
                    424: {
                    425:   /* write the byte to the self-expanding memory log - when we have the whole
                    426:      field's worth of data we then sift through the data (see the
                    427:      documentation on the GNM log format) and then pass it to ui_writelog */
                    428: 
                    429:   sound_logdata[sound_logdata_p++] = c;
                    430:   if (sound_logdata_p >= sound_logdata_size) {
                    431:     LOG_VERBOSE(("sound log buffer limit increased"));
                    432:     sound_logdata_size+= 8192;
                    433:     sound_logdata = realloc(sound_logdata, sound_logdata_size);
                    434:     if (!sound_logdata)
                    435:       ui_err("out of memory");
                    436:   }
                    437: }

unix.superglobalmegacorp.com

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