|
|
1.1.1.8 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.8 root 3: *
1.1 root 4: * Support for Linux/USS sound
1.1.1.8 root 5: *
1.1 root 6: * Copyright 1997 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "options.h"
13: #include "memory.h"
1.1.1.4 root 14: #include "events.h"
1.1 root 15: #include "custom.h"
16: #include "gensound.h"
17: #include "sounddep/sound.h"
1.1.1.9 ! root 18: #include "threaddep/thread.h"
1.1 root 19:
20: #include <sys/ioctl.h>
21:
22: #ifdef HAVE_SYS_SOUNDCARD_H
23: #include <sys/soundcard.h>
24: #elif defined HAVE_MACHINE_SOUNDCARD_H
25: #include <machine/soundcard.h>
26: #else
27: #error "Something went wrong during configuration."
28: #endif
29:
1.1.1.9 ! root 30: static smp_comm_pipe to_sound_pipe;
! 31: static uae_sem_t sound_comm_sem;
! 32:
! 33: static int sound_fd;
1.1.1.3 root 34: static int have_sound = 0;
1.1.1.9 ! root 35: static int dont_block;
1.1 root 36: static unsigned long formats;
37:
1.1.1.9 ! root 38: static int which_buffer;
! 39: static uae_u16 sndbuffer[2][44100];
! 40: uae_u16 *sndbufpt, *sndbuf_base;
1.1 root 41: int sndbufsize;
42:
1.1.1.2 root 43: static int exact_log2 (int v)
1.1 root 44: {
45: int l = 0;
46: while ((v >>= 1) != 0)
47: l++;
48: return l;
49: }
50:
1.1.1.9 ! root 51: void finish_sound_buffers (void)
! 52: {
! 53: dont_block = currprefs.m68k_speed == -1;
! 54: write_comm_pipe_int (&to_sound_pipe, 2, 1);
! 55: uae_sem_wait (&sound_comm_sem);
! 56: sndbufpt = sndbuf_base = sndbuffer[which_buffer ^= 1];
! 57: }
! 58:
1.1.1.2 root 59: void close_sound (void)
1.1 root 60: {
61: if (have_sound)
1.1.1.2 root 62: close (sound_fd);
1.1.1.9 ! root 63:
! 64: write_comm_pipe_int (&to_sound_pipe, 1, 1);
! 65: uae_sem_wait (&sound_comm_sem);
! 66: uae_sem_destroy (&sound_comm_sem);
1.1 root 67: }
68:
1.1.1.3 root 69: /* Try to determine whether sound is available. This is only for GUI purposes. */
1.1.1.2 root 70: int setup_sound (void)
1.1 root 71: {
72: sound_fd = open ("/dev/dsp", O_WRONLY);
1.1.1.3 root 73:
74: sound_available = 0;
75:
76: if (sound_fd < 0) {
77: perror ("Can't open /dev/dsp");
78: if (errno == EBUSY) {
79: /* We can hope, can't we ;) */
80: sound_available = 1;
81: return 1;
82: }
1.1 root 83: return 0;
1.1.1.3 root 84: }
1.1 root 85:
86: if (ioctl (sound_fd, SNDCTL_DSP_GETFMTS, &formats) == -1) {
1.1.1.3 root 87: perror ("ioctl failed - can't use sound");
88: close (sound_fd);
1.1 root 89: return 0;
90: }
91:
92: sound_available = 1;
1.1.1.3 root 93: close (sound_fd);
1.1 root 94: return 1;
95: }
96:
1.1.1.9 ! root 97: static void open_sound (void)
1.1 root 98: {
99: int tmp;
100: int rate;
101: int dspbits;
102:
1.1.1.3 root 103: sound_fd = open ("/dev/dsp", O_WRONLY);
104: have_sound = !(sound_fd < 0);
105: if (! have_sound) {
106: perror ("Can't open /dev/dsp");
107: if (errno != EBUSY)
108: sound_available = 0;
1.1.1.9 ! root 109: return;
1.1.1.3 root 110: }
111: if (ioctl (sound_fd, SNDCTL_DSP_GETFMTS, &formats) == -1) {
112: perror ("ioctl failed - can't use sound");
1.1.1.9 ! root 113: goto out_err;
1.1.1.3 root 114: }
115:
1.1 root 116: if (currprefs.sound_maxbsiz < 128 || currprefs.sound_maxbsiz > 16384) {
1.1.1.2 root 117: fprintf (stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz);
1.1 root 118: currprefs.sound_maxbsiz = 8192;
119: }
120:
1.1.1.2 root 121: tmp = 0x00040000 + exact_log2 (currprefs.sound_maxbsiz);
1.1 root 122: ioctl (sound_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
123: ioctl (sound_fd, SNDCTL_DSP_GETBLKSIZE, &sndbufsize);
124:
1.1.1.9 ! root 125: dspbits = 16;
1.1 root 126: ioctl (sound_fd, SNDCTL_DSP_SAMPLESIZE, &dspbits);
127: ioctl (sound_fd, SOUND_PCM_READ_BITS, &dspbits);
1.1.1.9 ! root 128: if (dspbits != 16) {
! 129: fprintf (stderr, "Can't use sound with 16 bits\n");
! 130: goto out_err;
1.1 root 131: }
132:
1.1.1.7 root 133: tmp = currprefs.sound_stereo;
1.1 root 134: ioctl (sound_fd, SNDCTL_DSP_STEREO, &tmp);
135:
136: rate = currprefs.sound_freq;
137: ioctl (sound_fd, SNDCTL_DSP_SPEED, &rate);
138: ioctl (sound_fd, SOUND_PCM_READ_RATE, &rate);
139: /* Some soundcards have a bit of tolerance here. */
140: if (rate < currprefs.sound_freq * 90 / 100 || rate > currprefs.sound_freq * 110 / 100) {
1.1.1.2 root 141: fprintf (stderr, "Can't use sound with desired frequency %d\n", currprefs.sound_freq);
1.1.1.9 ! root 142: goto out_err;
1.1 root 143: }
144:
1.1.1.9 ! root 145: obtainedfreq = rate;
1.1 root 146:
1.1.1.9 ! root 147: if (!(formats & AFMT_S16_NE))
! 148: goto out_err;
! 149: init_sound_table16 ();
! 150: sample_handler = currprefs.sound_stereo ? sample16s_handler : sample16_handler;
! 151:
! 152: sound_available = 1;
! 153: printf ("Sound driver found and configured at %d Hz, buffer is %d bytes (%d ms).\n",
! 154: rate, sndbufsize, sndbufsize * 1000 / (rate * 2 * (currprefs.sound_stereo ? 2 : 1)));
! 155: sndbufpt = sndbuf_base = sndbuffer[which_buffer = 0];
! 156:
! 157: return;
! 158:
! 159: out_err:
! 160: close (sound_fd);
! 161: have_sound = 0;
! 162: return;
! 163: }
! 164:
! 165: static void *sound_thread (void *dummy)
! 166: {
! 167: for (;;) {
! 168: int cmd = read_comm_pipe_int_blocking (&to_sound_pipe);
! 169: int n;
! 170:
! 171: switch (cmd) {
! 172: case 0:
! 173: open_sound ();
! 174: uae_sem_post (&sound_comm_sem);
! 175: break;
! 176: case 1:
! 177: uae_sem_post (&sound_comm_sem);
1.1 root 178: return 0;
1.1.1.9 ! root 179: case 2:
! 180: /* If trying for maximum CPU speed, don't block the main
! 181: thread, instead set the blocking_on_sound variable. If
! 182: not trying for maximum CPU speed, synchronize here by
! 183: delaying the sem_post until after the write. */
! 184: blocking_on_sound = dont_block;
! 185: if (dont_block)
! 186: uae_sem_post (&sound_comm_sem);
! 187:
! 188: write (sound_fd, sndbuffer[which_buffer], sndbufsize);
! 189: if (!dont_block)
! 190: uae_sem_post (&sound_comm_sem);
! 191:
! 192: blocking_on_sound = 0;
! 193: break;
! 194: }
1.1 root 195: }
1.1.1.9 ! root 196: }
1.1.1.8 root 197:
1.1.1.9 ! root 198: /* We use a thread so that we can use the time spent waiting for the sound
! 199: driver for executing m68k instructions, rather than just blocking. */
! 200: static void init_sound_thread (void)
! 201: {
! 202: uae_thread_id tid;
! 203:
! 204: init_comm_pipe (&to_sound_pipe, 20, 1);
! 205: uae_sem_init (&sound_comm_sem, 0, 0);
! 206: uae_start_thread (sound_thread, NULL, &tid);
! 207: }
! 208:
! 209: int init_sound (void)
! 210: {
! 211: init_sound_thread ();
! 212: write_comm_pipe_int (&to_sound_pipe, 0, 1);
! 213: uae_sem_wait (&sound_comm_sem);
! 214:
! 215: return have_sound;
1.1 root 216: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.