root/sweep/trunk/src/driver_oss.c

Revision 687, 9.4 kB (checked in by erikd, 2 years ago)

Remove redundant function parameter to driver_write function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
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
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <math.h>
34 #include <sys/ioctl.h>
35 #include <pthread.h>
36 #include <errno.h>
37
38 #include <glib.h>
39 #include <gtk/gtk.h>
40
41 #include <sweep/sweep_types.h>
42 #include <sweep/sweep_sample.h>
43
44 #include "driver.h"
45 #include "question_dialogs.h"
46 #include "preferences.h"
47
48 #include "pcmio.h"
49
50 #ifdef DRIVER_OSS
51
52 #include <sys/soundcard.h>
53
54 #ifdef DEVEL_CODE
55 /*#define DEBUG*/
56 #endif
57
58 /* #define DEBUG_OFFSET */
59
60 typedef struct _oss_play_offset oss_play_offset;
61
62 struct _oss_play_offset {
63   int framenr;
64   sw_framecount_t offset;
65 };
66
67
68 static oss_play_offset offsets[1<<LOG_FRAGS_MAX];
69
70 static int nfrags = 0;
71
72
73 /*static char * configured_devicename = DEV_DSP;*/
74
75 static int oindex;
76 static int current_frame;
77 static int frame;
78
79 static sw_handle oss_handle = {
80  0, -1, 0, 0, NULL
81 };
82
83 /* driver functions */
84
85 static GList *
86 oss_get_names (void)
87 {
88   GList * names = NULL;
89
90   names = g_list_append (names, "/dev/dsp");
91   names = g_list_append (names, "/dev/dsp1");
92   names = g_list_append (names, "/dev/sound/dsp");
93
94   return names;
95 }
96
97 static sw_handle *
98 oss_open (int monitoring, int flags)
99 {
100   char * dev_name;
101   int dev_dsp;
102   sw_handle * handle = &oss_handle;
103   int i;
104
105   if (monitoring) {
106     if (pcmio_get_use_monitor())
107       dev_name = pcmio_get_monitor_dev ();
108     else
109       return NULL;
110   } else {
111     dev_name = pcmio_get_main_dev ();
112   }
113
114   flags &= O_RDONLY|O_WRONLY|O_RDWR; /* mask out direction flags */
115
116   if((dev_dsp = open(dev_name, flags, 0)) == -1) {
117     sweep_perror (errno, "Unable to open device %s", dev_name);
118     return NULL;
119   }
120
121   handle->driver_flags = flags;
122   handle->driver_fd = dev_dsp;
123
124   oindex = 0;
125   current_frame = 0;
126   for (i = 0; i < (LOGFRAGS_TO_FRAGS(LOG_FRAGS_MAX)); i++) {
127     offsets[i].framenr = 0;
128     offsets[i].offset = -1;
129   }
130   frame = 0;
131
132   return handle;
133 }
134
135 static void
136 oss_setup (sw_handle * handle, sw_format * format)
137 {
138   int dev_dsp;
139   /*  int mask, format, stereo, frequency;*/
140
141   int stereo = 0;
142   int bits;
143   int i, want_channels, channels;
144   int srate;
145   int error;
146   int fragsize, frag;
147   int fmt;
148
149   if (handle == NULL) {
150 #ifdef DEBUG
151     g_print ("handle NULL in setup()\n");
152 #endif
153     return;
154   }
155
156   dev_dsp = handle->driver_fd;
157
158   if (ioctl (dev_dsp, SNDCTL_DSP_STEREO, &stereo) == -1) {
159     /* Fatal error */
160     perror("open_dsp_device 2 ") ;
161     exit (1);
162   } ;
163
164   if (ioctl (dev_dsp, SNDCTL_DSP_RESET, 0)) {
165     perror ("open_dsp_device 3 ") ;
166     exit (1) ;
167   } ;
168
169   nfrags = LOGFRAGS_TO_FRAGS(pcmio_get_log_frags());
170   fragsize = 8;
171   frag = (nfrags << 16) | fragsize;
172   if ((error = ioctl (dev_dsp, SNDCTL_DSP_SETFRAGMENT, &frag)) != 0) {
173     perror ("OSS: error setting fragments");
174   }
175
176   fragsize = (frag & 0xffff);
177   nfrags = (frag & 0x7fff000)>>16;
178 #ifdef DEBUG
179   g_print ("Got %d frags of size 2^%d\n", nfrags, fragsize);
180 #endif
181    
182   bits = 16 ;
183   if ((error = ioctl (dev_dsp, SOUND_PCM_WRITE_BITS, &bits)) != 0) {
184     perror ("open_dsp_device 4 ");
185     exit (1);
186   }
187
188   for (i=1; i <= format->channels; i *= 2) {
189     channels = format->channels / i;
190     want_channels = channels;
191
192     if ((error = ioctl (dev_dsp, SOUND_PCM_WRITE_CHANNELS, &channels)) == -1) {
193       perror ("open_dsp_device 5 ") ;
194       exit (1) ;
195     }
196
197     if (channels == want_channels) break;
198   }
199
200   handle->driver_channels = channels;
201
202   srate = format->rate;
203
204   if ((error = ioctl (dev_dsp, SOUND_PCM_WRITE_RATE, &srate)) != 0) {
205     perror ("open_dsp_device 6 ") ;
206     exit (1) ;
207   }
208
209   handle->driver_rate = srate;
210
211   if ((error = ioctl (dev_dsp, SNDCTL_DSP_SYNC, 0)) != 0) {
212     perror ("open_dsp_device 7 ") ;
213     exit (1) ;
214   }
215
216   fmt = AFMT_QUERY;
217   if ((error = ioctl (dev_dsp, SOUND_PCM_SETFMT, &fmt)) != 0) {
218     perror ("open_dsp_device 8") ;
219     exit (1) ;
220   }
221
222   handle->custom_data = GINT_TO_POINTER(0);
223
224 #ifdef WORDS_BIGENDIAN
225   if (fmt == AFMT_S16_LE || fmt == AFMT_U16_LE) {
226     handle->custom_data = GINT_TO_POINTER(1);
227   }
228 #else
229   if (fmt == AFMT_S16_BE || fmt == AFMT_U16_BE) {
230     handle->custom_data = GINT_TO_POINTER(1);
231   }
232 #endif
233
234 #ifdef DEBUG
235   {
236     int caps;
237
238     if (ioctl (dev_dsp, SNDCTL_DSP_GETCAPS, &caps) == -1) {
239       sweep_perror (errno, "OSS: Unable to get device capabilities");
240     }
241     /* CAP_REALTIME tells whether or not this device can give exact
242      * DMA pointers via GETOSPACE/GETISPACE. If this is true, then
243      * the device reports with byte accuracy. If it is false it reports
244      * to at least the nearest fragment bound, which is still pretty
245      * good for small fragments, so it's not much of a problem if
246      * this capability is not present.
247      */
248     g_print ("Realtime: %s\n", caps & DSP_CAP_REALTIME ? "YES" : "NO");
249   }
250 #endif
251 }
252
253 #define RECORD_SCALE (SW_AUDIO_T_MAX / 32768.0)
254
255 static int
256 oss_wait (sw_handle * handle)
257 {
258   return 0;
259 }
260
261 static ssize_t
262 oss_read (sw_handle * handle, sw_audio_t * buf, size_t count)
263 {
264   gint16 * bbuf;
265   size_t byte_count;
266   ssize_t bytes_read;
267   int need_bswap;
268   int i;
269
270   byte_count = count * sizeof (gint16);
271   bbuf = alloca (byte_count);
272   bytes_read = read (handle->driver_fd, bbuf, byte_count);
273
274   if (bytes_read == -1) {
275     sweep_perror (errno, "Error reading from OSS audio device");
276     return -1;
277   }
278
279   need_bswap = GPOINTER_TO_INT(handle->custom_data);
280
281   if (need_bswap) {
282     unsigned char * ucptr = (unsigned char *)bbuf;
283     unsigned char temp;
284    
285     for (i = 0; i < count; i++) {
286       temp = ucptr[2 * i];
287       ucptr[2 * i] = ucptr [2 * i + 1];
288       ucptr[2 * i + 1] = temp;
289     }
290   }
291
292   for (i = 0; i < count; i++) {
293     buf[i] = (sw_audio_t)(bbuf[i] * RECORD_SCALE);
294   }
295
296   return (bytes_read / sizeof (gint16));
297 }
298
299 #define PLAYBACK_SCALE (32768 / SW_AUDIO_T_MAX)
300
301 static ssize_t
302 oss_write (sw_handle * handle, sw_audio_t * buf, size_t count)
303 {
304   gint16 * bbuf;
305   size_t byte_count;
306   ssize_t bytes_written;
307   int need_bswap;
308   int i;
309
310   if (handle == NULL) {
311 #ifdef DEBUG
312     g_print ("handle NULL in write()\n");
313 #endif
314     return -1;
315   }
316
317   current_frame += count;
318   offsets[oindex].framenr = current_frame;
319   offsets[oindex].offset = -1;
320   oindex++; oindex %= nfrags;
321
322   byte_count = count * sizeof (gint16);
323   bbuf = alloca (byte_count);
324
325   for (i = 0; i < count; i++) {
326     bbuf[i] = (gint16)(PLAYBACK_SCALE * buf[i]);
327   }
328
329   need_bswap = GPOINTER_TO_INT(handle->custom_data);
330
331   if (need_bswap) {
332     unsigned char * ucptr = (unsigned char *)bbuf;
333     unsigned char temp;
334    
335     for (i = 0; i < count; i++) {
336       temp = ucptr[2 * i];
337       ucptr[2 * i] = ucptr [2 * i + 1];
338       ucptr[2 * i + 1] = temp;
339     }
340   }
341
342   bytes_written = write (handle->driver_fd, bbuf, byte_count);
343
344   if (bytes_written == -1) {
345     sweep_perror (errno, "Error writing to OSS audio device");
346     return -1;
347   } else {
348     return (bytes_written / sizeof(gint16));
349   }
350 }
351
352 static sw_framecount_t
353 oss_offset (sw_handle * handle)
354 {
355   count_info info;
356   int i, o;
357
358   if (handle == NULL) {
359 #ifdef DEBUG
360     g_print ("handle NULL in offset()\n");
361 #endif
362     return -1;
363   }
364
365   if (ioctl (handle->driver_fd, SNDCTL_DSP_GETOPTR, &info) == -1) {
366 #ifdef DEBUG_OFFSET
367     g_print ("error in GETOPTR\n");
368 #endif
369     return -1;
370   }
371
372   frame = info.bytes;
373 #ifdef DEBUG_OFFSET
374   g_print ("frame: %d\n", frame);
375 #endif
376
377   o = oindex+1;
378   for (i = 0; i < nfrags; i++) {
379     o %= nfrags;
380 #ifdef DEBUG_OFFSET
381     g_print ("\t(%d) Checking %d: %d\n", frame, o, offsets[o].framenr);
382 #endif
383     if (offsets[o].framenr >= frame) {
384       return offsets[o].offset;
385     }
386     o++;
387   }
388
389   return -1;
390 }
391
392 static void
393 oss_reset (sw_handle * handle)
394 {
395   if (handle == NULL) {
396 #ifdef DEBUG
397     g_print ("handle NULL in reset()\n");
398 #endif
399     return;
400   }
401
402   if(ioctl (handle->driver_fd, SNDCTL_DSP_RESET, 0) == -1) {
403     sweep_perror (errno, "Error resetting OSS audio device");
404   }
405 }
406
407 static void
408 oss_flush (sw_handle * handle)
409 {
410 }
411
412 void
413 oss_drain (sw_handle * handle)
414 {
415   if (handle == NULL) {
416     g_print ("handle NULL in drain ()\n");
417     return;
418   }
419
420   if(ioctl (handle->driver_fd, SNDCTL_DSP_POST, 0) == -1) {
421     sweep_perror (errno, "POST error on OSS audio device");
422   }
423
424   if (ioctl (handle->driver_fd, SNDCTL_DSP_SYNC, 0) == -1) {
425     sweep_perror (errno, "SYNC error on OSS audio device");
426   }
427 }
428
429 static void
430 oss_close (sw_handle * handle)
431 {
432   close (handle->driver_fd);
433   handle->driver_fd = -1;
434 }
435
436 static sw_driver _driver_oss = {
437   "OSS",
438   oss_get_names,
439   oss_open,
440   oss_setup,
441   oss_wait,
442   oss_read,
443   oss_write,
444   oss_offset,
445   oss_reset,
446   oss_flush,
447   oss_drain,
448   oss_close,
449   "oss_primary_device",
450   "oss_monitor_device",
451   "oss_log_frags"
452 };
453
454 #else
455
456 static sw_driver _driver_oss = {
457   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
458 };
459
460 #endif
461
462 sw_driver * driver_oss = &_driver_oss;
Note: See TracBrowser for help on using the browser.