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 esd_a.c by Avatar <avatar@deva.net>
21 based on linux_a.c
22
23 Functions to play sound through EsounD
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #define _GNU_SOURCE
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <dlfcn.h>
35
36 #ifndef NO_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41
42 #include <esd.h>
43
44 #include "timidity.h"
45 #include "common.h"
46 #include "output.h"
47 #include "controls.h"
48 #include "timer.h"
49 #include "instrum.h"
50 #include "playmidi.h"
51 #include "miditrace.h"
52
53 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
54 static void close_output(void);
55 static int output_data(char *buf, int32 nbytes);
56 static int acntl(int request, void *arg);
57 static int detect(void);
58
59
60 /* export the playback mode */
61
62 #define dpm esd_play_mode
63
64 PlayMode dpm = {
65 DEFAULT_RATE,
66 PE_16BIT|PE_SIGNED,
67 PF_PCM_STREAM/*|PF_CAN_TRACE*/,
68 -1,
69 {0}, /* default: get all the buffer fragments you can */
70 "Enlightened sound daemon", 'e',
71 "esd",
72 open_output,
73 close_output,
74 output_data,
75 acntl,
76 detect
77 };
78
79
try_open(void)80 static int try_open(void)
81 {
82 int include_enc, exclude_enc;
83 esd_format_t esdformat;
84
85 include_enc = 0;
86 exclude_enc = PE_ULAW|PE_ALAW|PE_BYTESWAP; /* They can't mean these */
87 if(dpm.encoding & PE_16BIT)
88 include_enc |= PE_SIGNED;
89 else
90 exclude_enc |= PE_SIGNED;
91 dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
92
93 /* Open the audio device */
94 esdformat = (dpm.encoding & PE_16BIT) ? ESD_BITS16 : ESD_BITS8;
95 esdformat |= (dpm.encoding & PE_MONO) ? ESD_MONO : ESD_STEREO;
96 return esd_play_stream(esdformat,dpm.rate,NULL,"timidity");
97 }
98
99
detect(void)100 static int detect(void)
101 {
102 int fd;
103
104 setenv("ESD_NO_SPAWN", "1", 0);
105 fd = try_open();
106 if (fd < 0)
107 return 0;
108 close(fd);
109 return 1; /* found */
110 }
111
112 /*************************************************************************/
113 /* We currently only honor the PE_MONO bit, and the sample rate. */
114
open_output(void)115 static int open_output(void)
116 {
117 int fd;
118
119 fd = try_open();
120
121 if(fd < 0)
122 {
123 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
124 dpm.name, strerror(errno));
125 return -1;
126 }
127
128
129 dpm.fd = fd;
130
131 return 0;
132 }
133
output_data(char * buf,int32 nbytes)134 static int output_data(char *buf, int32 nbytes)
135 {
136 int n;
137
138 // write(1, buf, nbytes);return 0;
139
140 while(nbytes > 0)
141 {
142 if((n = write(dpm.fd, buf, nbytes)) == -1)
143 {
144 ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
145 "%s: %s", dpm.name, strerror(errno));
146 if(errno == EWOULDBLOCK)
147 {
148 /* It is possible to come here because of bug of the
149 * sound driver.
150 */
151 continue;
152 }
153 return -1;
154 }
155 buf += n;
156 nbytes -= n;
157 }
158
159 return 0;
160 }
161
close_output(void)162 static void close_output(void)
163 {
164 if(dpm.fd == -1)
165 return;
166 close(dpm.fd);
167 dpm.fd = -1;
168 }
169
acntl(int request,void * arg)170 static int acntl(int request, void *arg)
171 {
172 switch(request)
173 {
174 case PM_REQ_DISCARD:
175 esd_audio_flush();
176 return 0;
177
178 case PM_REQ_RATE: {
179 /* not implemented yet */
180 break;
181 }
182
183 case PM_REQ_PLAY_START: /* Called just before playing */
184 case PM_REQ_PLAY_END: /* Called just after playing */
185 return 0;
186 }
187 return -1;
188 }
189