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 raw_audio.c
21
22 Functions to output raw sound data to a file or stdout.
23
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdio.h>
30
31 #ifdef __POCC__
32 #include <sys/types.h>
33 #endif //for off_t
34
35 #ifdef __W32__
36 #include <stdlib.h>
37 #include <io.h>
38 #endif
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43
44 #ifdef STDC_HEADERS
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48 #elif HAVE_STRINGS_H
49 #include <strings.h>
50 #endif
51
52 #include <fcntl.h>
53
54 #ifdef __FreeBSD__
55 #include <stdio.h>
56 #endif
57
58 #include "timidity.h"
59 #include "common.h"
60 #include "output.h"
61 #include "controls.h"
62 #include "instrum.h"
63 #include "playmidi.h"
64 #include "readmidi.h"
65
66 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
67 static void close_output(void);
68 static int output_data(char *buf, int32 bytes);
69 static int acntl(int request, void *arg);
70
71 /* export the playback mode */
72
73 #define dpm raw_play_mode
74
75 PlayMode dpm = {
76 DEFAULT_RATE, PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_FILE_OUTPUT,
77 -1,
78 {0,0,0,0,0},
79 "Raw waveform data", 'r',
80 NULL,
81 open_output,
82 close_output,
83 output_data,
84 acntl
85 };
86
87 /*************************************************************************/
88
89 /*
90 * Get the filename extention from the encoding
91 * This extension is available for sox.
92 */
encoding_ext(int32 encoding)93 static const char *encoding_ext(int32 encoding) {
94 static char ext[5], *p;
95
96 if(encoding & PE_ULAW) {
97 return ".ul";
98 }
99 if(encoding & PE_ALAW) {
100 return ".raw"; /* ?? */
101 }
102
103 p = ext;
104 *p++ = '.';
105 if(encoding & PE_SIGNED)
106 *p++ = 's';
107 else
108 *p++ = 'u';
109 if(encoding & PE_16BIT)
110 *p++ = 'w';
111 else if(encoding & PE_24BIT)
112 *p++ = '2', *p++ = '4'; /* is there any common extension? */
113 else
114 *p++ = 'b';
115 *p = '\0';
116 return ext;
117 }
118
raw_output_open(const char * fname)119 static int raw_output_open(const char *fname)
120 {
121 int fd;
122
123 if(strcmp(fname, "-") == 0)
124 return 1; /* data to stdout */
125 if((fd = open(fname, FILE_OUTPUT_MODE)) < 0)
126 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
127 fname, strerror(errno));
128 return fd;
129 }
130
auto_raw_output_open(const char * input_filename)131 static int auto_raw_output_open(const char *input_filename)
132 {
133
134 char *output_filename = (char *)safe_malloc(strlen(input_filename) + 5);
135 char *ext, *p;
136
137 strcpy(output_filename, input_filename);
138 if((ext = strrchr(output_filename, '.')) == NULL)
139 ext = output_filename + strlen(output_filename);
140 else {
141 /* strip ".gz" */
142 if(strcasecmp(ext, ".gz") == 0) {
143 *ext = '\0';
144 if((ext = strrchr(output_filename, '.')) == NULL)
145 ext = output_filename + strlen(output_filename);
146 }
147 }
148
149 /* replace '.' and '#' before ext */
150 for(p = output_filename; p < ext; p++)
151 if(*p == '.' || *p == '#')
152 *p = '_';
153
154 if(*ext && isupper(*(ext + 1))) {
155 strcpy(ext, encoding_ext(dpm.encoding));
156 ext++;
157 while(*ext) {
158 if(islower(*ext))
159 *ext = toupper(*ext);
160 ext++;
161 }
162 } else
163 strcpy(ext, encoding_ext(dpm.encoding));
164 if((dpm.fd = raw_output_open(output_filename)) < 0) {
165 free(output_filename);
166 return -1;
167 }
168 if(dpm.name != NULL)
169 free(dpm.name);
170 dpm.name = output_filename;
171 ctl->cmsg(CMSG_INFO, VERB_NORMAL, "Output %s", dpm.name);
172 return 0;
173
174 }
175
open_output(void)176 static int open_output(void)
177 {
178 dpm.encoding = validate_encoding(dpm.encoding, 0, 0);
179
180 if(dpm.name == NULL) {
181 if (!current_file_info || !current_file_info->filename)
182 return -1;
183 dpm.flag |= PF_AUTO_SPLIT_FILE;
184 } else {
185 dpm.flag &= ~PF_AUTO_SPLIT_FILE;
186 if((dpm.fd = raw_output_open(dpm.name)) == -1)
187 return -1;
188 }
189
190 return 0;
191 }
192
output_data(char * buf,int32 bytes)193 static int output_data(char *buf, int32 bytes)
194 {
195 int n;
196
197 if(dpm.fd == -1)
198 return -1;
199
200 while(((n = std_write(dpm.fd, buf, bytes)) == -1) && errno == EINTR)
201 ;
202 if(n == -1)
203 {
204 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
205 dpm.name, strerror(errno));
206 return -1;
207 }
208 return n;
209 }
210
close_output(void)211 static void close_output(void)
212 {
213 if(dpm.fd != 1 && dpm.fd != -1) /* We don't close stdout */
214 close(dpm.fd);
215 dpm.fd = -1;
216 }
217
acntl(int request,void * arg)218 static int acntl(int request, void *arg)
219 {
220 switch(request) {
221 case PM_REQ_PLAY_START:
222 if(dpm.flag & PF_AUTO_SPLIT_FILE)
223 return auto_raw_output_open(current_file_info->filename);
224 return 0;
225 case PM_REQ_PLAY_END:
226 if(dpm.flag & PF_AUTO_SPLIT_FILE)
227 close_output();
228 return 0;
229 case PM_REQ_DISCARD:
230 return 0;
231 }
232 return -1;
233 }
234