|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.