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