1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
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     ao_a.c
21 	Written by Iwata <b6330015@kit.jp>
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif /* HAVE_CONFIG_H */
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 
31 #include <ao/ao.h>
32 
33 #include "timidity.h"
34 #include "output.h"
35 #include "controls.h"
36 #include "timer.h"
37 #include "instrum.h"
38 #include "playmidi.h"
39 #include "miditrace.h"
40 #include "common.h"
41 
42 static int opt_ao_device_id = -2;
43 
44 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
45 static void close_output(void);
46 static int output_data(char *buf, int32 nbytes);
47 static int acntl(int request, void *arg);
48 static int detect(void);
49 static void ao_set_options(int, ao_option **);
50 static void safe_ao_append_option(ao_option **, const char *, const char *);
51 
52 /* export the playback mode */
53 
54 #define dpm ao_play_mode
55 
56 PlayMode dpm = {
57   DEFAULT_RATE, PE_SIGNED|PE_16BIT, PF_PCM_STREAM,
58   -1,
59   {0}, /* default: get all the buffer fragments you can */
60   "Libao mode", 'O',
61   NULL, /* edit your ~/.libao */
62   open_output,
63   close_output,
64   output_data,
65   acntl,
66   detect
67 };
68 
69 static ao_device *ao_device_ctx;
70 
safe_ao_append_option(ao_option ** options,const char * key,const char * value)71 static void safe_ao_append_option(ao_option **options, const char *key,
72                                   const char *value)
73 {
74   if (ao_append_option(options, key, value) == 1) return;
75   else {
76     ctl->cmsg(CMSG_FATAL, VERB_NORMAL,
77               "Fatal error: ao_append_option has failed to allocate memory");
78 #ifdef ABORT_AT_FATAL
79     abort();
80 #endif /* ABORT_AT_FATAL */
81     safe_exit(10);
82     /*NOTREACHED*/
83   }
84 }
85 
ao_set_options(int driver_id,ao_option ** options)86 static void ao_set_options(int driver_id, ao_option **options)
87 {
88   char *opt_string, *p, *token, *value;
89   const char *env_ao_opts = getenv ("TIMIDITY_AO_OPTIONS");
90 
91   if (env_ao_opts == NULL) return;
92 
93   opt_string = safe_strdup(env_ao_opts);
94   p = opt_string;
95 
96   while (p) {
97     token = p;
98     p = strchr(token, ',');
99     if (p != NULL) *p++ = '\0';
100     value = strchr(token, '=');
101     if ((value == NULL) || (value == token)) continue;
102     *value = '\0';
103     safe_ao_append_option(options, token, value+1);
104   }
105 
106   free(opt_string);
107 }
108 
109 static ao_sample_format ao_sample_format_ctx;
110 
show_ao_device_info(FILE * fp)111 static void show_ao_device_info(FILE *fp)
112 {
113   int driver_count;
114   ao_info **devices;
115   int i;
116 
117   ao_initialize();
118 
119   devices  = ao_driver_info_list(&driver_count);
120   if (driver_count < 1) {
121 	  fputs("*no device found*" NLS, fp);
122   }
123   else {
124 	  for(i = 0; i < driver_count; i++) {
125 		  if (devices[i]->type == AO_TYPE_LIVE)
126 			  fprintf(fp, "%d %s \n", ao_driver_id(devices[i]->short_name), devices[i]->short_name);
127 	  }
128   }
129   ao_shutdown();
130 }
131 
132 
open_output(void)133 static int open_output(void)
134 {
135   int driver_id, ret = 0;
136 
137   int driver_count;
138   ao_info **devices;
139   ao_option *options = NULL;
140   int i;
141 
142   ao_initialize();
143 
144   opt_ao_device_id = -2;
145   devices  = ao_driver_info_list(&driver_count);
146   if ((driver_count > 0) && (dpm.name != NULL)) {
147     for(i = 0; i < driver_count; i++) {
148       if(  (devices[i]->type == AO_TYPE_LIVE)
149         && (strcmp(dpm.name, devices[i]->short_name) == 0)  ){
150         opt_ao_device_id = ao_driver_id(dpm.name);
151       }
152     }
153   }
154 
155   if (opt_ao_device_id == -2){
156     if(dpm.name != NULL)
157       ret = sscanf(dpm.name, "%d", &opt_ao_device_id);
158     if ( dpm.name == NULL || ret == 0 || ret == EOF)
159       opt_ao_device_id = -2;
160   }
161 
162   if (opt_ao_device_id == -1){
163     ao_shutdown();
164     show_ao_device_info(stdout);
165     return -1;
166   }
167 
168   if (opt_ao_device_id==-2) {
169     driver_id = ao_default_driver_id();
170   }
171   else {
172     ao_info *device;
173 
174     driver_id = opt_ao_device_id;
175     if ((device = ao_driver_info(driver_id)) == NULL) {
176       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: driver is not supported.",
177 		dpm.name);
178       return -1;
179     }
180     if (device->type == AO_TYPE_FILE) {
181       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: file output is not supported.",
182 		dpm.name);
183       return -1;
184     }
185   }
186 
187   if (driver_id == -1) {
188     ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
189 	      dpm.name, strerror(errno));
190     return -1;
191   }
192 
193   /* They can't mean these */
194   dpm.encoding &= ~(PE_ULAW|PE_ALAW|PE_BYTESWAP);
195 
196   ao_sample_format_ctx.channels = (dpm.encoding & PE_MONO) ? 1 : 2;
197   ao_sample_format_ctx.rate = dpm.rate;
198   ao_sample_format_ctx.byte_format = AO_FMT_NATIVE;
199   ao_sample_format_ctx.bits = (dpm.encoding & PE_24BIT) ? 24 : 0;
200   ao_sample_format_ctx.bits = (dpm.encoding & PE_16BIT) ? 16 : 0;
201   if (ao_sample_format_ctx.bits == 0)
202     ao_sample_format_ctx.bits = 8;
203 
204   ao_set_options(driver_id, &options);
205 
206   if ((ao_device_ctx = ao_open_live(driver_id, &ao_sample_format_ctx, options)) == NULL) {
207     ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
208 	      dpm.name, strerror(errno));
209     ao_free_options(options);
210     return -1;
211   }
212   ao_free_options(options);
213   return 0;
214 }
215 
output_data(char * buf,int32 nbytes)216 static int output_data(char *buf, int32 nbytes)
217 {
218   if (ao_play(ao_device_ctx, buf, nbytes) == 0) {
219     ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "%s: %s",
220 	      dpm.name, strerror(errno));
221     return -1;
222   }
223   return 0;
224 }
225 
close_output(void)226 static void close_output(void)
227 {
228   if (ao_device_ctx != NULL) {
229     ao_close(ao_device_ctx);
230     ao_device_ctx = NULL;
231     ao_shutdown();
232   }
233 }
234 
acntl(int request,void * arg)235 static int acntl(int request, void *arg)
236 {
237   switch(request) {
238   case PM_REQ_DISCARD:
239   case PM_REQ_PLAY_START: /* Called just before playing */
240   case PM_REQ_PLAY_END: /* Called just after playing */
241     return 0;
242   }
243   return -1;
244 }
245 
detect(void)246 static int detect(void)
247 {
248   int driver_id, result = 0;
249   ao_sample_format ao_sample_format_ctx;
250   ao_device *ao_device_ctx;
251 
252   ao_initialize();
253 
254   /* Only succeed in autodetect mode when pulseaudio is available! */
255   driver_id = ao_driver_id("pulse");
256 
257   ao_sample_format_ctx.rate = 44100;
258   ao_sample_format_ctx.bits = 16;
259   ao_sample_format_ctx.channels = 2;
260   ao_sample_format_ctx.byte_format = AO_FMT_NATIVE;
261   ao_sample_format_ctx.matrix = NULL;
262 
263   if ((ao_device_ctx = ao_open_live(driver_id, &ao_sample_format_ctx, NULL))) {
264     result = 1;
265     ao_close(ao_device_ctx);
266   }
267 
268   ao_shutdown();
269 
270   return result;
271 }
272