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