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