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

1.1     ! root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
        !             2: 
        !             3: #include <sys/types.h>
        !             4: #include <sys/stat.h>
        !             5: #include <sys/ioctl.h>
        !             6: #include <sys/time.h>
        !             7: #include <string.h>
        !             8: #include <stdio.h>
        !             9: #include <fcntl.h>
        !            10: #include <errno.h>
        !            11: #include <unistd.h>
        !            12: #include <math.h>
        !            13: 
        !            14: #include "generator.h"
        !            15: #include "gensound.h"
        !            16: #include "vdp.h"
        !            17: #include "ui.h"
        !            18: 
        !            19: #ifdef JFM
        !            20: #  include "jfm.h"
        !            21: #else
        !            22: #  include "support.h"
        !            23: #  include "fm.h"
        !            24: #endif
        !            25: 
        !            26: #include <sys/soundcard.h>
        !            27: 
        !            28: /*** variables externed ***/
        !            29: 
        !            30: int sound_feedback = 0;           /* -1, running out of sound
        !            31:                                      +0, lots of sound, do something */
        !            32: int sound_debug = 0;              /* 0 for no debug, 1 for debug */
        !            33: int sound_minfields = 5;          /* minimum fields to try to keep buffered */
        !            34: int sound_maxfields = 10;         /* max fields to buffer before blocking */
        !            35: uint8 sound_regs1[256];
        !            36: uint8 sound_regs2[256];
        !            37: uint8 sound_address1 = 0;
        !            38: uint8 sound_address2 = 0;
        !            39: uint8 sound_keys[8];
        !            40: 
        !            41: /* SN76489 snd_cpu; */
        !            42: 
        !            43: /*** forward references ***/
        !            44: 
        !            45: /* void snd_sndout(int chan, int freq, int vol); */
        !            46: 
        !            47: /*** file scoped variables ***/
        !            48: 
        !            49: #define SOUND_MAXRATE 44100
        !            50: #define SOUND_FRAGMENTS 12
        !            51: 
        !            52: static unsigned int sound_sampsperfield = 0;
        !            53: static int sound_dev = -1;
        !            54: /* static int sound_dump = 0; */
        !            55: static uint16 soundbuf[2][SOUND_MAXRATE/50]; /* pal is lowest framerate */
        !            56: static int sound_active = 0;
        !            57: static int sound_format;
        !            58: static int sound_stereo;
        !            59: static int sound_speed;
        !            60: static int sound_frag;
        !            61: static int sound_fragsize;
        !            62: static unsigned int sound_threshold; /* bytes in buffer we're trying for */
        !            63: 
        !            64: #ifdef JFM
        !            65:   static t_jfm_ctx *sound_ctx;
        !            66: #endif
        !            67: 
        !            68: /*** sound_init - initialise this sub-unit ***/
        !            69: 
        !            70: int sound_init(void)
        !            71: {
        !            72:   int ret;
        !            73: 
        !            74:   ret = sound_start();
        !            75:   if (ret)
        !            76:     return ret;
        !            77: #ifdef JFM
        !            78:   if ((sound_ctx = jfm_init(0, 2612, vdp_clock/7, sound_speed,
        !            79:                            NULL, NULL)) == NULL) {
        !            80: #else
        !            81:   if (YM2612Init(1, vdp_clock/7, sound_speed, NULL, NULL)) {
        !            82: #endif
        !            83:     close(sound_dev);
        !            84:     return 1;
        !            85:   }
        !            86:   LOG_VERBOSE(("YM2612 Initialised @ sample rate %d", sound_speed));
        !            87:   return 0;
        !            88: }
        !            89: 
        !            90: /*** sound_final - finalise this sub-unit ***/
        !            91: 
        !            92: void sound_final(void)
        !            93: {
        !            94:   sound_stop();
        !            95: #ifdef JFM
        !            96:   jfm_final(sound_ctx);
        !            97: #else
        !            98:   YM2612Shutdown();
        !            99: #endif
        !           100: }
        !           101: 
        !           102: /*** sound_start - start sound hardware ***/
        !           103: 
        !           104: int sound_start(void)
        !           105: {
        !           106:   audio_buf_info sound_info;
        !           107: 
        !           108:   /* The threshold parameter specifies how many fields worth of sound we
        !           109:      should try and keep around (a display field is 1/50th or 1/60th of a
        !           110:      second) - generator works by trying to keep threshold number of fields
        !           111:      worth of sound around, and drops plotting frames to keep up on slow
        !           112:      machines */
        !           113: 
        !           114:   if (sound_active)
        !           115:     sound_stop();
        !           116:   LOG_VERBOSE(("Initialising sound..."));
        !           117:   sound_sampsperfield = SOUND_SAMPLERATE / vdp_framerate;
        !           118: 
        !           119:   /* sound_dump = open("/tmp/sound_dump", O_CREAT|O_WRONLY|O_TRUNC); */
        !           120: 
        !           121:   if ((sound_dev = open(SOUND_DEVICE, O_WRONLY, 0)) == -1) {
        !           122:     LOG_CRITICAL(("open " SOUND_DEVICE " failed: %s", strerror(errno)));
        !           123:     return 1;
        !           124:   }
        !           125:   sound_frag = (sound_maxfields<<16 |
        !           126:                (int)(ceil(log10(sound_sampsperfield*4)/log10(2))));
        !           127:   if (ioctl(sound_dev, SNDCTL_DSP_SETFRAGMENT, &sound_frag) == -1) {
        !           128:     LOG_CRITICAL(("Error setting fragment size: %s", strerror(errno)));
        !           129:     close(sound_dev);
        !           130:     return 1;
        !           131:   }
        !           132:   sound_format = AFMT_S16_LE;
        !           133:   if (ioctl(sound_dev, SNDCTL_DSP_SETFMT, &sound_format) == -1) {
        !           134:     LOG_CRITICAL(("Error setting sound device format: %s", strerror(errno)));
        !           135:     close(sound_dev);
        !           136:     return 1;
        !           137:   }
        !           138:   if (sound_format != AFMT_S16_LE && sound_format != AFMT_S16_BE) {
        !           139:     LOG_CRITICAL(("Sound device format not supported (must be 16 bit)"));
        !           140:     close(sound_dev);
        !           141:     return 1;
        !           142:   }
        !           143:   sound_stereo = 1;
        !           144:   if (ioctl(sound_dev, SNDCTL_DSP_STEREO, &sound_stereo) == -1) {
        !           145:     LOG_CRITICAL(("Error setting stereo: %s", strerror(errno)));
        !           146:     close(sound_dev);
        !           147:     return 1;
        !           148:   }
        !           149:   if (sound_stereo != 1) {
        !           150:     LOG_CRITICAL(("Sound device does not support stereo"));
        !           151:     close(sound_dev);
        !           152:     return 1;
        !           153:   }
        !           154:   sound_speed = SOUND_SAMPLERATE;
        !           155:   if (ioctl(sound_dev, SNDCTL_DSP_SPEED, &sound_speed) == -1) {
        !           156:     LOG_CRITICAL(("Error setting sound speed: %s",  strerror(errno)));
        !           157:     close(sound_dev);
        !           158:     return 1;
        !           159:   }
        !           160:   if (sound_speed != SOUND_SAMPLERATE) {
        !           161:     if (abs(sound_speed-SOUND_SAMPLERATE) > 50) {
        !           162:       LOG_NORMAL(("Warning: Sample rate not exactly 22050"));
        !           163:     } else {
        !           164:       LOG_CRITICAL(("Sound device does not support sample rate %d "
        !           165:                    "(returned %d)", SOUND_SAMPLERATE, sound_speed));
        !           166:       close(sound_dev);
        !           167:       return 1;
        !           168:     }
        !           169:   }
        !           170:   if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1) {
        !           171:     LOG_CRITICAL(("Error getting output space info", strerror(errno)));
        !           172:     close(sound_dev);
        !           173:     return 1;
        !           174:   }
        !           175:   LOG_VERBOSE(("Total allocated fragments = %d (requested %d)",
        !           176:               sound_info.fragstotal, sound_maxfields));
        !           177:   LOG_VERBOSE(("Fragment size = %d (requested %d)", sound_info.fragsize,
        !           178:               sound_sampsperfield*4));
        !           179:   LOG_VERBOSE(("Bytes free in buffer = %d", sound_info.bytes));
        !           180:   sound_threshold = sound_sampsperfield*4*sound_minfields;
        !           181:   LOG_VERBOSE(("Theshold = %d (%d fields of sound === %dms latency)",
        !           182:               sound_threshold, sound_minfields,
        !           183:               (int)(1000*(float)sound_minfields/(float)vdp_framerate)));
        !           184:   if ((signed)sound_threshold >= sound_info.bytes) {
        !           185:     LOG_CRITICAL(("Threshold exceeds bytes free in buffer"));
        !           186:     close(sound_dev);
        !           187:     return 1;
        !           188:   }
        !           189:   sound_active = 1;
        !           190:   return 0;
        !           191: }
        !           192: /*** sound_stop - stop sound ***/
        !           193: 
        !           194: void sound_stop(void)
        !           195: {
        !           196:   if (!sound_active)
        !           197:     return;
        !           198:   LOG_VERBOSE(("Stopping sound..."));
        !           199:   if (sound_dev != -1)
        !           200:     close(sound_dev);
        !           201:   sound_dev = -1;
        !           202:   sound_active = 0;
        !           203:   LOG_VERBOSE(("Stopped sound."));
        !           204: }
        !           205:   
        !           206: /*** sound_reset - reset sound sub-unit ***/
        !           207: 
        !           208: int sound_reset(void)
        !           209: {
        !           210:   sound_final();
        !           211:   return sound_init();
        !           212: }
        !           213: 
        !           214: /*** sound_genreset - reset genesis sound ***/
        !           215: 
        !           216: void sound_genreset(void)
        !           217: {
        !           218: #ifdef JFM
        !           219:   jfm_reset(sound_ctx);
        !           220: #else
        !           221:   YM2612ResetChip(0);
        !           222: #endif
        !           223: }
        !           224: 
        !           225: /*** sound_process - process sound ***/
        !           226: 
        !           227: void sound_process(void)
        !           228: {
        !           229:   static sint16 *tbuf[2];
        !           230:   int s1 = (sound_sampsperfield*(vdp_line))/vdp_totlines;
        !           231:   int s2 = (sound_sampsperfield*(vdp_line+1))/vdp_totlines;
        !           232: 
        !           233:   tbuf[0] = soundbuf[0] + s1;
        !           234:   tbuf[1] = soundbuf[1] + s1;
        !           235: 
        !           236:   /* printf("YM2612: %d to %d\n", s1, s2); */
        !           237: 
        !           238:   if (s2 > s1)
        !           239: #ifdef JFM
        !           240:     jfm_update(sound_ctx, (void **)tbuf, s2 - s1);
        !           241: #else
        !           242:     YM2612UpdateOne(0, (void **)tbuf, s2 -s1);
        !           243: #endif
        !           244: }
        !           245: 
        !           246: /*** sound_endfield - end frame and output sound ***/
        !           247: 
        !           248: void sound_endfield(void)
        !           249: {
        !           250:   unsigned int i;
        !           251:   uint16 buffer[(SOUND_MAXRATE/50)*2]; /* pal is slowest framerate */
        !           252: #ifdef WORDS_BIGENDIAN
        !           253:   int endian = 1;
        !           254: #else
        !           255:   int endian = 0;
        !           256: #endif
        !           257:   audio_buf_info sound_info;
        !           258:   unsigned int pending;
        !           259:   struct timeval tv;
        !           260: 
        !           261:   if (ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &sound_info) == -1)
        !           262:     ui_err("Error getting output space info", strerror(errno));
        !           263:   pending = (sound_info.fragstotal*sound_info.fragsize)-sound_info.bytes;
        !           264:   if (pending < sound_threshold)
        !           265:     sound_feedback = -1;
        !           266:   else
        !           267:     sound_feedback = 0;
        !           268:   if (sound_debug) {
        !           269:     LOG_VERBOSE(("End of field - sound card says output buffer left = %d bytes",
        !           270:                  sound_info.bytes));
        !           271:     LOG_VERBOSE(("Sound card says %d frags @ %d bytes each = %d bytes",
        !           272:                  sound_info.fragstotal, sound_info.fragsize,
        !           273:                  sound_info.fragstotal*sound_info.fragsize));
        !           274:     LOG_VERBOSE(("Therefore, pending = %d, compare with threshold %d = %d",
        !           275:                  pending, sound_threshold, sound_feedback));
        !           276:   }
        !           277:   if (sound_format == AFMT_S16_LE && endian == 0) {
        !           278:     /* device matches endianness of host */
        !           279:     for (i = 0; i < sound_sampsperfield; i++) {
        !           280:       buffer[i*2] = soundbuf[0][i];
        !           281:       buffer[i*2+1] = soundbuf[1][i];
        !           282:     }
        !           283:   } else {
        !           284:     /* device is odd and is different to host endianness */
        !           285:     for (i = 0; i < sound_sampsperfield; i++) {
        !           286:       buffer[i*2] = (soundbuf[0][i] >> 8) | ((soundbuf[0][i] << 8) & 0xff00);
        !           287:       buffer[i*2+1] = (soundbuf[1][i] >> 8) | ((soundbuf[1][i] << 8) & 0xff00);
        !           288:     }
        !           289:   }
        !           290:   if (sound_debug) {
        !           291:     gettimeofday(&tv, NULL);
        !           292:     LOG_REQUEST(("%ld:%ld - before write", tv.tv_sec, tv.tv_usec));
        !           293:   }
        !           294:   if (write(sound_dev, buffer, sound_sampsperfield*4) == -1) {
        !           295:     if (errno != EINTR)
        !           296:       ui_err("Error writing to sound device: %s", strerror(errno));
        !           297:   }
        !           298:   /*
        !           299:   if (write(sound_dump, buffer, sound_sampsperfield*4) == -1)
        !           300:     ui_err("Error writing to dump file: %s", strerror(errno));
        !           301:   */
        !           302:   if (sound_debug) {
        !           303:     gettimeofday(&tv, NULL);
        !           304:     LOG_REQUEST(("%ld:%ld - after write", tv.tv_sec, tv.tv_usec));
        !           305:   }
        !           306: }
        !           307: 
        !           308: /*** sound_ym2612fetch - fetch byte from ym2612 chip ***/
        !           309: 
        !           310: uint8 sound_ym2612fetch(uint8 addr)
        !           311: {
        !           312: #ifdef JFM
        !           313:   return jfm_read(sound_ctx, addr);
        !           314: #else
        !           315:   return YM2612Read(0, addr);
        !           316: #endif
        !           317: }
        !           318: 
        !           319: /*** sound_ym2612store - store a byte to the ym2612 chip ***/
        !           320: 
        !           321: void sound_ym2612store(uint8 addr, uint8 data)
        !           322: {
        !           323:   switch (addr) {
        !           324:   case 0:
        !           325:     sound_address1 = data;
        !           326:     break;
        !           327:   case 1:
        !           328:     if (sound_address1 == 0x28 && (data & 3) != 3)
        !           329:       sound_keys[data & 7] = data >> 4;
        !           330:     if (sound_address1 == 0x2a) {
        !           331:       sound_keys[7] = 0;
        !           332:     }
        !           333:     if (sound_address1 == 0x2b)
        !           334:       sound_keys[7] = data & 0x80 ? 0xf : 0;
        !           335:     sound_regs1[sound_address1] = data;
        !           336:     break;
        !           337:   case 2:
        !           338:     sound_address2 = data;
        !           339:     break;
        !           340:   case 3:
        !           341:     sound_regs2[sound_address2] = data;
        !           342:     break;
        !           343:   }
        !           344: #ifdef JFM
        !           345:   jfm_write(sound_ctx, addr, data);
        !           346: #else
        !           347:   YM2612Write(0, addr, data);
        !           348: #endif
        !           349: }
        !           350: 

unix.superglobalmegacorp.com

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