source: roaraudio/roard/driver_sndio.c @ 2370:20fe0615bbe9

Last change on this file since 2370:20fe0615bbe9 was 2370:20fe0615bbe9, checked in by phi, 15 years ago

added MIDI support to sndio output driver

File size: 6.7 KB
Line 
1//driver_sndio.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26#ifdef ROAR_HAVE_LIBSNDIO
27
28int driver_sndio_init_vio(struct roar_vio_calls * vio, struct driver_sndio * inst) {
29 if ( vio == NULL )
30  return -1;
31
32 memset(vio, 0, sizeof(struct roar_vio_calls));
33
34 vio->close    = driver_sndio_close_vio;
35 vio->write    = driver_sndio_write;
36 vio->sync     = driver_sndio_sync;
37 vio->ctl      = driver_sndio_ctl;
38
39 vio->inst     = (void*) inst;
40
41 return 0;
42}
43
44#define er() if ( self->shandle ) sio_close(self->shandle); \
45             if ( self->mhandle ) mio_close(self->mhandle); \
46             if ( self->device  ) free(self->device);       \
47             free(self);                                    \
48             return -1
49
50int driver_sndio_open(struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh, struct roar_stream_server * sstream) {
51 struct driver_sndio * self = NULL;
52
53 if ( (self = malloc(sizeof(struct driver_sndio))) == NULL ) {
54  ROAR_ERR("driver_sndio_open(*): Can not malloc() instance data: %s", strerror(errno));
55  return -1;
56 }
57
58 memset(self, 0, sizeof(struct driver_sndio));
59 memcpy(&(self->info), info, sizeof(struct roar_audio_info));
60
61 self->ssid = -1;
62
63 if ( sstream == NULL ) {
64  self->stream = NULL;
65  self->dir    = ROAR_DIR_OUTPUT;
66 } else {
67  self->stream = sstream;
68  self->dir    = ROAR_STREAM(sstream)->dir;
69
70  switch (self->dir) {
71   case ROAR_DIR_OUTPUT:
72   case ROAR_DIR_MONITOR:
73     self->dir = ROAR_DIR_OUTPUT;
74    break;
75   case ROAR_DIR_MIDI_OUT:
76     info->channels = 16;
77     info->codec    = ROAR_CODEC_MIDI;
78     info->bits     = 8;
79    break;
80   default:
81     er();
82  }
83 }
84
85 if ( device != NULL )
86  self->device = strdup(device);
87
88 if ( driver_sndio_init_vio(inst, self) == -1 ) {
89  ROAR_ERR("driver_sndio_open(*): Can not init vio interface");
90  er();
91 }
92
93 if ( driver_sndio_open_device(self) == -1 ) {
94  ROAR_ERR("driver_sndio_open(*): Can not open audio device");
95  er();
96 }
97
98 ROAR_DBG("driver_sndio_open(*): sndio devices opened :)");
99
100 return 0;
101}
102#undef er
103
104int     driver_sndio_close_vio    (struct roar_vio_calls * vio) {
105 struct driver_sndio * self = vio->inst;
106
107 if ( self->shandle != NULL )
108  sio_close(self->shandle);
109
110 if ( self->mhandle != NULL )
111  mio_close(self->mhandle);
112
113 if ( self->device != NULL )
114  free(self->device);
115
116 free(self);
117
118 return 0;
119}
120
121int     driver_sndio_open_device  (struct driver_sndio * self) {
122
123 ROAR_DBG("driver_sndio_open_device(*) = ?");
124 switch (self->dir) {
125  case ROAR_DIR_OUTPUT:
126    if ( (self->shandle = sio_open(self->device, SIO_PLAY, 0)) == NULL ) {
127     ROAR_ERR("driver_sndio_open_device(*): Can not open sndio audio device");
128     return -1;
129    }
130   self->need_config = 1;
131   break;
132  case ROAR_DIR_MIDI_OUT:
133    if ( (self->mhandle = mio_open(self->device, MIO_OUT, 0)) == NULL ) {
134     ROAR_ERR("driver_sndio_open_device(*): Can not open sndio MIDI device");
135     return -1;
136    }
137   break;
138  default:
139    return -1;
140 }
141
142 ROAR_DBG("driver_sndio_open_device(*) = ?");
143 return 0;
144}
145
146int     driver_sndio_config_device(struct driver_sndio * self) {
147 struct sio_par par;
148
149 sio_initpar(&par);
150
151 par.bits  = self->info.bits;
152 par.rate  = self->info.rate;
153 par.pchan = self->info.channels;
154
155 switch (self->info.codec) {
156  case ROAR_CODEC_PCM_S_LE:
157    par.le  = 1;
158    par.sig = 1;
159   break;
160  case ROAR_CODEC_PCM_S_BE:
161    par.le  = 0;
162    par.sig = 1;
163   break;
164  case ROAR_CODEC_PCM_U_LE:
165    par.le  = 1;
166    par.sig = 0;
167   break;
168  case ROAR_CODEC_PCM_U_BE:
169    par.le  = 0;
170    par.sig = 0;
171   break;
172  default:
173    return -1;
174   break;
175 }
176
177 if ( sio_setpar(self->shandle, &par) == 0 ) {
178  ROAR_ERR("driver_sndio_config_device(*): Can not set stream parameters");
179  return -1;
180 }
181
182 if ( sio_start(self->shandle) == 0 ) {
183  ROAR_ERR("driver_sndio_config_device(*): Can not start stream");
184  return -1;
185 }
186
187 self->need_config = 0;
188
189 return 0;
190}
191
192int     driver_sndio_reopen_device(struct driver_sndio * self) {
193 return -1;
194}
195
196ssize_t driver_sndio_write        (struct roar_vio_calls * vio, void *buf, size_t count) {
197 struct driver_sndio * self = vio->inst;
198
199 ROAR_DBG("driver_sndio_write(*) = ?");
200
201 if ( self->need_config ) {
202  if ( driver_sndio_config_device(vio->inst) == -1 ) {
203   return -1;
204  }
205 }
206
207 ROAR_DBG("driver_sndio_write(*) = ?");
208
209 switch (self->dir) {
210  case ROAR_DIR_OUTPUT:
211    return sio_write(self->shandle, buf, count);
212   break;
213  case ROAR_DIR_MIDI_OUT:
214    return mio_write(self->mhandle, buf, count);
215   break;
216 }
217
218 ROAR_WARN("driver_sndio_write(*): Driver changed direction to something not supported, this should not happen");
219
220 return -1;
221}
222
223int     driver_sndio_sync         (struct roar_vio_calls * vio) {
224 return -1;
225}
226
227#define data(x) x: if ( data == NULL ) return -1;
228#define no_data(x) x: if ( data != NULL ) return -1;
229
230int     driver_sndio_ctl          (struct roar_vio_calls * vio, int cmd, void * data) {
231 struct driver_sndio * self = vio->inst;
232 unsigned d;
233
234 switch (cmd) {
235  case data(ROAR_VIO_CTL_SET_SSTREAMID)
236    self->ssid = *(int *)data;
237   break;
238  case data(ROAR_VIO_CTL_SET_SSTREAM)
239    // FIXME: we should do some better error handling here:
240    if ( ROAR_STREAM(data)->dir != self->dir ) return -1;
241    self->stream = data;
242   break;
243  case data(ROAR_VIO_CTL_GET_AUINFO)
244    memcpy(data, &(self->info), sizeof(struct roar_audio_info));
245   break;
246  case data(ROAR_VIO_CTL_SET_AUINFO)
247    memcpy(&(self->info), data, sizeof(struct roar_audio_info));
248    return driver_sndio_reopen_device(self);
249   break;
250  case ROAR_VIO_CTL_SET_VOLUME:
251    switch (self->info.channels) {
252     case 1:
253       d = ROAR_MIXER(data)->mixer[0] * SIO_MAXVOL / ROAR_MIXER(data)->scale;
254      break;
255     case 2:
256       if ( ROAR_MIXER(data)->mixer[0] != ROAR_MIXER(data)->mixer[1] )
257        return -1;
258       d = ROAR_MIXER(data)->mixer[0] * SIO_MAXVOL / ROAR_MIXER(data)->scale;
259      break;
260     default:
261      return -1;
262    }
263    return sio_setvol(self->shandle, d) == 0 ? -1 : 0;
264   break;
265  default:
266    return -1;
267   break;
268 }
269
270 return 0;
271}
272
273#endif
274
275//ll
Note: See TracBrowser for help on using the repository browser.