ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/audio_oss_esd.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/audio_oss_esd.cpp (file contents):
Revision 1.1 by cebix, 1999-10-23T17:57:45Z vs.
Revision 1.7 by cebix, 2001-07-05T20:30:51Z

# Line 1 | Line 1
1   /*
2   *  audio_oss_esd.cpp - Audio support, implementation for OSS and ESD (Linux and FreeBSD)
3   *
4 < *  Basilisk II (C) 1997-1999 Christian Bauer
4 > *  Basilisk II (C) 1997-2001 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 41 | Line 41
41   #include "audio.h"
42   #include "audio_defs.h"
43  
44 < #if ENABLE_ESD
44 > #ifdef ENABLE_ESD
45   #include <esd.h>
46   #endif
47  
# Line 49 | Line 49
49   #include "debug.h"
50  
51  
52 < // Supported sample rates, sizes and channels
53 < int audio_num_sample_rates = 1;
54 < uint32 audio_sample_rates[] = {44100 << 16};
55 < int audio_num_sample_sizes = 1;
56 < uint16 audio_sample_sizes[] = {16};
57 < int audio_num_channel_counts = 1;
58 < uint16 audio_channel_counts[] = {2};
52 > // The currently selected audio parameters (indices in audio_sample_rates[] etc. vectors)
53 > static int audio_sample_rate_index = 0;
54 > static int audio_sample_size_index = 0;
55 > static int audio_channel_count_index = 0;
56  
57   // Constants
58   #define DSP_NAME "/dev/dsp"
# Line 63 | Line 60 | uint16 audio_channel_counts[] = {2};
60   // Global variables
61   static int audio_fd = -1;                                                       // fd of /dev/dsp or ESD
62   static int mixer_fd = -1;                                                       // fd of /dev/mixer
63 + static bool formats_known = false;                                      // Flag: available audio formats have been probed
64   static sem_t audio_irq_done_sem;                                        // Signal from interrupt to streaming thread: data block read
65   static bool sem_inited = false;                                         // Flag: audio_irq_done_sem initialized
66   static int sound_buffer_size;                                           // Size of sound buffer in bytes
67   static bool little_endian = false;                                      // Flag: DSP accepts only little-endian 16-bit sound data
68 + static uint8 silence_byte;                                                      // Byte value to use to fill sound buffers with silence
69   static pthread_t stream_thread;                                         // Audio streaming thread
70   static pthread_attr_t stream_thread_attr;                       // Streaming thread attributes
71   static bool stream_thread_active = false;                       // Flag: streaming thread installed
# Line 80 | Line 79 | static void *stream_func(void *arg);
79   *  Initialization
80   */
81  
82 + // Set AudioStatus to reflect current audio stream format
83 + static void set_audio_status_format(void)
84 + {
85 +        AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index];
86 +        AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index];
87 +        AudioStatus.channels = audio_channel_counts[audio_channel_count_index];
88 + }
89 +
90   // Init using /dev/dsp, returns false on error
91 < bool audio_init_dsp(void)
91 > static bool open_dsp(void)
92   {
93 +        // Open /dev/dsp
94 +        audio_fd = open(DSP_NAME, O_WRONLY);
95 +        if (audio_fd < 0) {
96 +                fprintf(stderr, "WARNING: Cannot open %s (%s)\n", DSP_NAME, strerror(errno));
97 +                return false;
98 +        }
99 +
100          printf("Using " DSP_NAME " audio output\n");
101  
102          // Get supported sample formats
103 <        unsigned long format;
104 <        ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
105 <        if ((format & (AFMT_U8 | AFMT_S16_BE | AFMT_S16_LE)) == 0) {
106 <                WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
107 <                close(audio_fd);
108 <                audio_fd = -1;
109 <                return false;
103 >        if (!formats_known) {
104 >                unsigned long format;
105 >                ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
106 >                if (format & AFMT_U8)
107 >                        audio_sample_sizes.push_back(8);
108 >                if (format & (AFMT_S16_BE | AFMT_S16_LE))
109 >                        audio_sample_sizes.push_back(16);
110 >
111 >                int stereo = 0;
112 >                if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 0)
113 >                        audio_channel_counts.push_back(1);
114 >                stereo = 1;
115 >                if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 1)
116 >                        audio_channel_counts.push_back(2);
117 >
118 >                if (audio_sample_sizes.empty() || audio_channel_counts.empty()) {
119 >                        WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
120 >                        close(audio_fd);
121 >                        audio_fd = -1;
122 >                        return false;
123 >                }
124 >
125 >                audio_sample_rates.push_back(11025 << 16);
126 >                audio_sample_rates.push_back(22050 << 16);
127 >                int rate = 44100;
128 >                ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
129 >                if (rate > 22050)
130 >                        audio_sample_rates.push_back(rate << 16);
131 >
132 >                // Default to highest supported values
133 >                audio_sample_rate_index = audio_sample_rates.size() - 1;
134 >                audio_sample_size_index = audio_sample_sizes.size() - 1;
135 >                audio_channel_count_index = audio_channel_counts.size() - 1;
136 >                formats_known = true;
137          }
97        if (format & (AFMT_S16_BE | AFMT_S16_LE))
98                audio_sample_sizes[0] = 16;
99        else
100                audio_sample_sizes[0] = 8;
101        if (!(format & AFMT_S16_BE))
102                little_endian = true;
138  
139          // Set DSP parameters
140 <        format = AudioStatus.sample_size == 8 ? AFMT_U8 : (little_endian ? AFMT_S16_LE : AFMT_S16_BE);
140 >        unsigned long format;
141 >        if (audio_sample_sizes[audio_sample_size_index] == 8) {
142 >                format = AFMT_U8;
143 >                little_endian = false;
144 >                silence_byte = 0x80;
145 >        } else {
146 >                unsigned long sup_format;
147 >                ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
148 >                if (sup_format & AFMT_S16_BE) {
149 >                        little_endian = false;
150 >                        format = AFMT_S16_BE;
151 >                } else {
152 >                        little_endian = true;
153 >                        format = AFMT_S16_LE;
154 >                }
155 >                silence_byte = 0;
156 >        }
157          ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format);
158          int frag = 0x0004000c;          // Block size: 4096 frames
159          ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag);
160 <        int stereo = (AudioStatus.channels == 2);
160 >        int stereo = (audio_channel_counts[audio_channel_count_index] == 2);
161          ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
162 <        int rate = AudioStatus.sample_rate >> 16;
162 >        int rate = audio_sample_rates[audio_sample_rate_index] >> 16;
163          ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
164  
165          // Get sound buffer size
166          ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &audio_frames_per_block);
167          D(bug("DSP_GETBLKSIZE %d\n", audio_frames_per_block));
117        sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
168          return true;
169   }
170  
171   // Init using ESD, returns false on error
172 < bool audio_init_esd(void)
172 > static bool open_esd(void)
173   {
174 < #if ENABLE_ESD
175 <        printf("Using ESD audio output\n");
174 > #ifdef ENABLE_ESD
175 >        // ESD supports a variety of audio formats
176 >        if (!formats_known) {
177 >                audio_sample_rates.push_back(11025 << 16);
178 >                audio_sample_rates.push_back(22050 << 16);
179 >                audio_sample_rates.push_back(44100 << 16);
180 >                audio_sample_sizes.push_back(8);
181 >                audio_sample_sizes.push_back(16);
182 >                audio_channel_counts.push_back(1);
183 >                audio_channel_counts.push_back(2);
184 >
185 >                // Default to 44.1kHz, 16-bit, stereo
186 >                audio_sample_rate_index = 2;
187 >                audio_sample_size_index = 1;
188 >                audio_channel_count_index = 1;
189 >                formats_known = true;
190 >        }
191  
192          // ESD audio format
193          esd_format_t format = ESD_STREAM | ESD_PLAY;
194 <        if (AudioStatus.sample_size == 8)
194 >        if (audio_sample_sizes[audio_sample_size_index] == 8)
195                  format |= ESD_BITS8;
196          else
197                  format |= ESD_BITS16;
198 <        if (AudioStatus.channels == 1)
198 >        if (audio_channel_counts[audio_channel_count_index] == 1)
199                  format |= ESD_MONO;
200          else
201                  format |= ESD_STEREO;
# Line 140 | Line 205 | bool audio_init_esd(void)
205   #else
206          little_endian = true;
207   #endif
208 +        silence_byte = 0;       // Is this correct for 8-bit mode?
209  
210          // Open connection to ESD server
211 <        audio_fd = esd_play_stream(format, AudioStatus.sample_rate >> 16, NULL, NULL);
211 >        audio_fd = esd_play_stream(format, audio_sample_rates[audio_sample_rate_index] >> 16, NULL, NULL);
212          if (audio_fd < 0) {
213 <                char str[256];
214 <                sprintf(str, GetString(STR_NO_ESD_WARN), strerror(errno));
149 <                WarningAlert(str);
213 >                fprintf(stderr, "WARNING: Cannot open ESD connection\n");
214 >                formats_known = false;
215                  return false;
216          }
217  
218 +        printf("Using ESD audio output\n");
219 +
220          // Sound buffer size = 4096 frames
221          audio_frames_per_block = 4096;
155        sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
222          return true;
157 #else
158        ErrorAlert("Basilisk II has been compiled with ESD support disabled.");
159        return false;
223   #endif
224   }
225  
226 < void AudioInit(void)
226 > static bool open_audio(void)
227   {
228 <        char str[256];
229 <
230 <        // Init audio status (defaults) and feature flags
231 <        AudioStatus.sample_rate = audio_sample_rates[0];
232 <        AudioStatus.sample_size = audio_sample_sizes[0];
233 <        AudioStatus.channels = audio_channel_counts[0];
171 <        AudioStatus.mixer = 0;
172 <        AudioStatus.num_sources = 0;
173 <        audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
174 <
175 <        // Sound disabled in prefs? Then do nothing
176 <        if (PrefsFindBool("nosound"))
177 <                return;
228 > #ifdef ENABLE_ESD
229 >        // If ESPEAKER is set, the user probably wants to use ESD, so try that first
230 >        if (getenv("ESPEAKER"))
231 >                if (open_esd())
232 >                        goto dev_opened;
233 > #endif
234  
235          // Try to open /dev/dsp
236 <        audio_fd = open(DSP_NAME, O_WRONLY);
237 <        if (audio_fd < 0) {
238 < #if ENABLE_ESD
239 <                if (!audio_init_esd())
240 <                        return;
241 < #else
242 <                sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), DSP_NAME, strerror(errno));
243 <                WarningAlert(str);
188 <                return;
236 >        if (open_dsp())
237 >                goto dev_opened;
238 >
239 > #ifdef ENABLE_ESD
240 >        // Hm, /dev/dsp failed so we try ESD again if ESPEAKER wasn't set
241 >        if (!getenv("ESPEAKER"))
242 >                if (open_esd())
243 >                        goto dev_opened;
244   #endif
190        } else
191                if (!audio_init_dsp())
192                        return;
245  
246 <        // Try to open /dev/mixer
247 <        mixer_fd = open("/dev/mixer", O_RDWR);
248 <        if (mixer_fd < 0)
197 <                printf("WARNING: Cannot open /dev/mixer (%s)", strerror(errno));
246 >        // No audio device succeeded
247 >        WarningAlert(GetString(STR_NO_AUDIO_WARN));
248 >        return false;
249  
250 <        // Init semaphore
251 <        if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
252 <                return;
253 <        sem_inited = true;
250 >        // Device opened, set AudioStatus
251 > dev_opened:
252 >        sound_buffer_size = (audio_sample_sizes[audio_sample_size_index] >> 3) * audio_channel_counts[audio_channel_count_index] * audio_frames_per_block;
253 >        set_audio_status_format();
254  
255          // Start streaming thread
256          pthread_attr_init(&stream_thread_attr);
# Line 212 | Line 263 | void AudioInit(void)
263                  pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
264          }
265   #endif
266 +        stream_thread_cancel = false;
267          stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
268  
269 <        // Everything OK
269 >        // Everything went fine
270          audio_open = true;
271 +        return true;
272 + }
273 +
274 + void AudioInit(void)
275 + {
276 +        char str[256];
277 +
278 +        // Init audio status (reasonable defaults) and feature flags
279 +        AudioStatus.sample_rate = 44100 << 16;
280 +        AudioStatus.sample_size = 16;
281 +        AudioStatus.channels = 2;
282 +        AudioStatus.mixer = 0;
283 +        AudioStatus.num_sources = 0;
284 +        audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
285 +
286 +        // Sound disabled in prefs? Then do nothing
287 +        if (PrefsFindBool("nosound"))
288 +                return;
289 +
290 +        // Init semaphore
291 +        if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
292 +                return;
293 +        sem_inited = true;
294 +
295 +        // Try to open /dev/mixer
296 +        mixer_fd = open("/dev/mixer", O_RDWR);
297 +        if (mixer_fd < 0)
298 +                printf("WARNING: Cannot open /dev/mixer (%s)", strerror(errno));
299 +
300 +        // Open and initialize audio device
301 +        open_audio();
302   }
303  
304  
# Line 223 | Line 306 | void AudioInit(void)
306   *  Deinitialization
307   */
308  
309 < void AudioExit(void)
309 > static void close_audio(void)
310   {
311          // Stop stream and delete semaphore
312          if (stream_thread_active) {
# Line 234 | Line 317 | void AudioExit(void)
317                  pthread_join(stream_thread, NULL);
318                  stream_thread_active = false;
319          }
237        if (sem_inited)
238                sem_destroy(&audio_irq_done_sem);
320  
321 <        // Close /dev/dsp
322 <        if (audio_fd > 0)
321 >        // Close /dev/dsp or ESD socket
322 >        if (audio_fd >= 0) {
323                  close(audio_fd);
324 +                audio_fd = -1;
325 +        }
326 +
327 +        audio_open = false;
328 + }
329 +
330 + void AudioExit(void)
331 + {
332 +        if (sem_inited) {
333 +                sem_destroy(&audio_irq_done_sem);
334 +                sem_inited = false;
335 +        }
336  
337          // Close /dev/mixer
338 <        if (mixer_fd > 0)
338 >        if (mixer_fd >= 0) {
339                  close(mixer_fd);
340 +                mixer_fd = -1;
341 +        }
342   }
343  
344  
# Line 277 | Line 372 | static void *stream_func(void *arg)
372   {
373          int16 *silent_buffer = new int16[sound_buffer_size / 2];
374          int16 *last_buffer = new int16[sound_buffer_size / 2];
375 <        memset(silent_buffer, 0, sound_buffer_size);
375 >        memset(silent_buffer, silence_byte, sound_buffer_size);
376  
377          while (!stream_thread_cancel) {
378                  if (AudioStatus.num_sources) {
# Line 310 | Line 405 | static void *stream_func(void *arg)
405                                                  for (int i=0; i<work_size/2; i++)
406                                                          last_buffer[i] = ntohs(p[i]);
407                                          } else
408 <                                                memcpy(last_buffer, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), work_size);
409 <                                        memset((uint8 *)last_buffer + work_size, 0, sound_buffer_size - work_size);
408 >                                                Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
409 >                                        memset((uint8 *)last_buffer + work_size, silence_byte, sound_buffer_size - work_size);
410                                          write(audio_fd, last_buffer, sound_buffer_size);
411                                  }
412                                  D(bug("stream: data written\n"));
# Line 356 | Line 451 | void AudioInterrupt(void)
451  
452   /*
453   *  Set sampling parameters
454 < *  "index" is an index into the audio_sample_rates[] etc. arrays
454 > *  "index" is an index into the audio_sample_rates[] etc. vectors
455   *  It is guaranteed that AudioStatus.num_sources == 0
456   */
457  
458 < void audio_set_sample_rate(int index)
458 > bool audio_set_sample_rate(int index)
459   {
460 +        close_audio();
461 +        audio_sample_rate_index = index;
462 +        return open_audio();
463   }
464  
465 < void audio_set_sample_size(int index)
465 > bool audio_set_sample_size(int index)
466   {
467 +        close_audio();
468 +        audio_sample_size_index = index;
469 +        return open_audio();
470   }
471  
472 < void audio_set_channels(int index)
472 > bool audio_set_channels(int index)
473   {
474 +        close_audio();
475 +        audio_channel_count_index = index;
476 +        return open_audio();
477   }
478  
479  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines