Big Endian Fixes like mad. Other fixes - Alex
[terminatorX.git] / src / tX_audiofile.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2002  Alexander K├Ânig
4  
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9  
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_audiofile.cc
20  
21     Description: This implements the new audiofile class. Unlike earlier
22                  versions of terminatorX where wav_read.c was evilishly
23                  "#ifdef"ed to support multiple loading strategies this new
24                  design allows multiple load_*()-methods/strategies at
25                  the same time. (e.g. tx can now try to load a wavfile
26                  with the builtin routines and if that fails it'll try
27                  to load the file through sox (if available)).
28 */   
29
30 #include "tX_audiofile.h"
31
32 #include <string.h>
33 #include <malloc.h>
34 #include "wav_file.h"
35 #include "tX_loaddlg.h"
36 #include "tX_endian.h"
37
38 tx_audiofile :: tx_audiofile()
39 {
40         mem_type=TX_AUDIO_UNDEFINED;
41         file_type=TX_FILE_UNDEFINED;
42         file=NULL;
43         strcpy(filename,"");
44         mem=NULL;
45         no_samples=0;
46 }
47
48 void tx_audiofile :: figure_file_type()
49 {
50         char *ext;
51         
52         ext=strrchr(filename, (int) '.');
53         
54 //      puts(ext);
55         if (ext)
56         {
57                 if (strlen(ext) >3)
58                 {
59                         ext++;
60                         if (!strcasecmp("wav", ext)) file_type=TX_FILE_WAV;
61                         else if (!strncasecmp("mp", ext, 2)) file_type=TX_FILE_MPG123;
62                         else if (!strncasecmp("ogg", ext, 2)) file_type=TX_FILE_OGG123;
63                 }
64         }
65 }
66
67 int tx_audiofile :: load(char *p_file_name)
68 {
69         int load_err=TX_AUDIO_ERR_NOT_SUPPORTED;
70         
71         strcpy(filename, p_file_name);
72         
73         ld_set_progress(0);
74                 
75         figure_file_type();
76         
77 #ifdef USE_BUILTIN_WAV
78         if ((load_err) && (file_type==TX_FILE_WAV))
79                 load_err=load_wav();
80         
81         if (!load_err) return(load_err);        
82 #endif  
83
84 #ifdef USE_MPG123_INPUT
85         if ((load_err) && (file_type==TX_FILE_MPG123))
86         {
87                 load_err=load_mpg123();
88                 return(load_err);
89         }
90 #endif  
91
92 #ifdef USE_OGG123_INPUT
93         if ((load_err) && (file_type==TX_FILE_OGG123))
94         {
95                 load_err=load_ogg123();
96                 return(load_err);
97         }
98 #endif
99
100 #ifdef USE_SOX_INPUT
101         if (load_err)
102         {
103                 load_err=load_sox();
104         }
105 #endif  
106
107         return(load_err);
108 }
109
110  tx_audiofile :: ~tx_audiofile()
111  {
112
113         // clear mem
114
115         switch (mem_type)
116         {
117                 case TX_AUDIO_MMAP:
118                 {
119                         // unmap stuff
120                 }
121                 
122                 case TX_AUDIO_LOAD:
123                 {
124                         //munlock(void *mem, memsize);
125                         free(mem);
126                 }
127                 
128         }       
129
130         // clear file
131
132         if (file)
133         {
134                 if (mem_type==TX_AUDIO_MMAP)
135                 {
136                         // free mmap
137                 }
138         }
139         
140  }
141  
142 typedef struct tembpuff
143 {
144         char buffer[SOX_BLOCKSIZE];
145         ssize_t used;
146         void *next; 
147 } tempbuff;
148
149 static tempbuff *newbuff()
150 {
151         tempbuff *nwbf;
152         
153         nwbf=(tempbuff *) malloc(sizeof(tempbuff));
154         nwbf->next=NULL;
155         nwbf->used=0;
156         
157         return(nwbf);
158 }
159
160 #ifdef NEED_PIPED 
161
162 int tx_audiofile :: load_piped()
163 {
164         int16_t *data;
165         int16_t *p;
166         ssize_t allbytes=0;
167         ssize_t bytes=1;
168         int i;
169         tempbuff* start=NULL;
170         tempbuff* w=NULL;
171         tempbuff* newb=NULL;
172         
173         start=newbuff();
174         w=start;
175
176         mem_type=TX_AUDIO_LOAD;
177
178         ld_set_progress(0.5);
179                 
180         while (bytes)
181         {       
182                 bytes = fread(w->buffer, 1, SOX_BLOCKSIZE, file);
183                 w->used=bytes;
184                 
185                 if (bytes)
186                 {
187                         newb=newbuff();
188                         if (!newb) return (TX_AUDIO_ERR_ALLOC);
189                         w->next=newb;
190                         w=newb;
191                 }                               
192
193                 allbytes+=bytes;                        
194         }
195         
196         pclose(file); file=NULL;
197         
198         if (!allbytes)  // Nothing read from pipe -> error
199         {
200                 free(start);
201                 return (TX_AUDIO_ERR_PIPE_READ);
202         }
203
204         no_samples=allbytes/sizeof(int16_t);
205         memsize=allbytes;
206         data = (int16_t *) malloc (memsize);
207         
208         if (!data)
209         {
210                 w=start;
211                 while (w)
212                 {
213                         newb=(tempbuff*)w->next;
214                         free(w);
215                         w=newb;
216                 }
217                 return(TX_AUDIO_ERR_ALLOC);
218         }
219         
220         w=start;
221         p=data;
222
223         bytes=0;
224         
225         while(w)
226         {
227                 memcpy(p, w->buffer, w->used);
228                 bytes+=w->used;
229                 newb=(tempbuff*) w->next;
230                 free(w);
231                 w=newb;
232                 
233                 ld_set_progress(0.5 + 0.5*((gfloat) bytes)/((gfloat) allbytes));
234                 
235                 p+=(ssize_t) SOX_BLOCKSIZE/sizeof(int16_t);
236         }
237
238         mem=data;
239         return (TX_AUDIO_SUCCESS);
240 }
241
242 #endif
243         
244 #ifdef USE_SOX_INPUT
245 int tx_audiofile :: load_sox()
246 {
247         char command[PATH_MAX*2];
248
249         sprintf(command, SOX_STR, filename);
250         file = popen(command, "r");
251         
252         if (!file) return TX_AUDIO_ERR_SOX;
253         
254         return load_piped();
255         
256 }
257 #endif  
258
259 #ifdef USE_MPG123_INPUT
260 int tx_audiofile :: load_mpg123()
261 {
262         char command[PATH_MAX*2];
263         
264         sprintf(command, MPG123_STR, filename);
265         file = popen(command, "r");
266         
267         if (!file) return TX_AUDIO_ERR_MPG123;
268         
269         return load_piped();
270 }
271 #endif  
272
273 #ifdef USE_OGG123_INPUT
274 int tx_audiofile :: load_ogg123()
275 {
276         char command[PATH_MAX*2];
277
278         sprintf(command, OGG123_STR, filename);
279         file = popen(command, "r");
280
281         if (!file) return TX_AUDIO_ERR_OGG123;
282
283         return load_piped();
284 }
285 #endif
286
287 #ifdef USE_BUILTIN_WAV
288 #define min(a,b) ((a) < (b) ? (a) : (b))
289 int tx_audiofile :: load_wav()
290 {
291         wav_sig wav_in;
292         int16_t *data;
293         int16_t *p;
294         ssize_t allbytes=0;
295         ssize_t bytes=0;
296         int i;
297
298         mem_type=TX_AUDIO_LOAD;
299         
300         if (!init_wav_read(filename, &wav_in))
301         {
302                 return(TX_AUDIO_ERR_WAV_NOTFOUND);
303         }
304
305 #ifdef USE_CONSOLE
306         printf("Loading: %s\n", filename);
307         if (parms.verbose) printf("File: %i Bytes Data, %i Bit Depth, %i Hz Samplerate.\n", wav_in.len, wav_in.depth, wav_in.srate);    
308 #endif  
309
310         if (wav_in.depth != 16)
311         {
312                 return(TX_AUDIO_ERR_NOT_16BIT);
313         }
314
315         if (wav_in.chans != 1)
316         {
317                 return(TX_AUDIO_ERR_NOT_MONO);
318         }
319
320 #ifdef USE_CONSOLE      
321         if (wav_in.srate != 44100) 
322         {
323                 puts("[load_wav] Warning: Wave-File was not recorded at 44.100 Hz!");
324         }
325         if (wav_in.blkalign != 2)
326         {
327                 printf("[load_wav] Warning: Unexpected block alignment: %i.\n", wav_in.blkalign);
328         }
329 #endif
330
331         memsize=wav_in.len;
332         data = (int16_t *) malloc (memsize);
333                 
334         if (!data)
335         {
336                 return(TX_AUDIO_ERR_ALLOC);
337         }
338
339         p=data;
340 #ifdef ENABLE_DEBUG_OUTPUT
341         int output=1;
342         unsigned char *debug_p=(unsigned char *) p;
343 #endif  
344         while (wav_in.len>allbytes)
345         {       
346                 bytes = fread(p, 1, min(1024, wav_in.len-allbytes), wav_in.handle);
347
348 #ifdef ENABLE_DEBUG_OUTPUT
349                 if (output) { tX_debug("tX_audiofile::load_wav() read %i Bytes [%04x %04x %04x %04x %04x %04x ..]", bytes, (unsigned int) p[0],  (unsigned int) p[1], (unsigned int) p[2], (unsigned int) p[3], (unsigned int) p[4], (unsigned int) p[5]); }
350 #endif
351
352                 if (bytes<=0) {
353                         free(data);
354                         return (TX_AUDIO_ERR_WAV_READ);
355                 }
356
357 #ifdef BIG_ENDIAN_MACHINE
358                 swapbuffer(p, bytes/sizeof(int16_t));
359 #       ifdef ENABLE_DEBUG_OUTPUT
360                 if (output) { tX_debug("tX_audiofile::load_wav() swapped %i Bytes [%04x %04x %04x %04x %04x %04x ..]",
361                 bytes, (unsigned int) p[0],  (unsigned int) p[1], (unsigned int) p[2], (unsigned int) p[3], (unsigned int) p[4], (unsigned int) p[5]); }
362 #       endif
363 #endif          
364
365 #ifdef ENABLE_DEBUG_OUTPUT
366                 output=0;
367 #endif
368
369                 allbytes+=bytes;
370                 
371                 ld_set_progress((float) allbytes/(float)wav_in.len);
372                 
373                 p+=(ssize_t) bytes/sizeof(int16_t);
374         }
375         
376         wav_close(wav_in.handle);
377
378         mem=data;
379         no_samples=memsize/sizeof(int16_t);
380         
381         return (TX_AUDIO_SUCCESS);
382 }
383 #endif