there is a new event api ...
[sound-tools/hdrec.git] / hdrec.c
1 /*
2  * hdrec -- some sort of multi tracker (not right now, but in the future :p)
3  *
4  * author: hackbard@hackdaworld.dyndns.org
5  *
6  */
7
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/select.h>
16 #include <sys/time.h>
17 #include <sys/soundcard.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <errno.h>
21
22 /* dfb */
23 #include <directfb.h>
24
25 #include "oss_api.h"
26 #include "hdrec.h"
27
28 /* fourier */
29 #include "fourier.h"
30
31 int usage(void) {
32         printf("usage:\n\n");
33         printf("-h \t\t print this help\n");
34         printf("-i \t\t use/print file info\n");
35         printf("-R \t\t play reversed :)\n");
36         printf("-d <device> \t sound device (eg: /dev/dsp)\n");
37         printf("-r <file> \t record to <file>\n");
38         printf("-p <file> \t play from <file>\n");
39         printf("-s \t\t stereo\n");
40         printf("-m \t\t mono\n");
41         printf("-f <format> \t 1=8bit - 2=16bit (le)\n");
42         printf("-F <hz> \t frequency\n");
43         printf("-c <src> <dst> \t converts raw to wav (specify f/m,s/F)\n");
44         
45         return 1;
46 }
47
48 int main(int argc,char **argv) {
49         int sfile_fd;
50         int pfile_fd;
51         int audio_fd;
52         char device[MAX_C_DEVICE];
53         int i,j,k;
54         int rw;
55         unsigned char mode=0;
56         int o_mode=0;
57         char record_file[MAX_C_FILE];
58         char play_file[MAX_C_FILE];
59         dsp_set set;
60         unsigned char *buf;
61         unsigned char *buf2=NULL;
62         unsigned char print_info=0;
63         unsigned char info[8];
64         int info_int;
65         int tmp;
66         char is_wav=0;
67         fd_set read_fds,write_fds;
68         struct timeval fds_tv;
69         char c;
70
71         /* dfb */
72         IDirectFB *dfb;
73         IDirectFBSurface *primary;
74         DFBSurfaceDescription dsc;
75         int width,height;
76
77         /* fourier */
78         t_fourier fourier;
79         int sample;
80         int dx;
81         int a_f;
82
83         /* defaults */
84         strcpy(device,"");
85         set.format=AFMT_S16_LE;
86         set.freq=44100;
87         set.channel=STEREO;
88
89         /* read argv */
90         for(i=1;i<argc;i++) {
91                 if(argv[i][0]=='-') {
92                         switch(argv[i][1]) {
93                                 case 'h':
94                                         usage();
95                                         return 1;
96                                 case 'i':
97                                         print_info=1;
98                                         break;
99                                 case 'r':
100                                         mode|=RECORD;
101                                         strcpy(record_file,argv[++i]);
102                                         break;
103                                 case 'p':
104                                         mode|=PLAY;
105                                         strcpy(play_file,argv[++i]);
106                                         break;
107                                 case 'R':
108                                         mode|=REVERSED;
109                                         break;
110                                 case 's':
111                                         set.channel=STEREO;
112                                         break;
113                                 case 'm':
114                                         set.channel=MONO;
115                                         break;
116                                 case 'f':
117                                         i++;
118                                         if(atoi(argv[i])==1) set.format=AFMT_U8;
119                                         if(atoi(argv[i])==2) set.format=AFMT_S16_LE;
120                                         break;
121                                 case 'F':
122                                         set.freq=atoi(argv[++i]);
123                                         break;
124                                 case 'd':
125                                         strncpy(device,argv[++i],MAX_C_DEVICE-1);
126                                         break;
127                                 case 'c':
128                                         mode=CONVERT;
129                                         strcpy(play_file,argv[++i]);
130                                         strcpy(record_file,argv[++i]);
131                                         break;
132                                 default:
133                                         usage();
134                                         return -1;
135                         }
136                 } else usage();
137         }
138
139         if(!strcmp("",device)) {
140                 printf("you have to specify a device!\n");
141                 return -1;
142         }
143
144         /* open audio fd */
145         if(mode&RECORD) o_mode=O_RDONLY;
146         if(mode&PLAY) o_mode=O_WRONLY;
147         if(mode&RECORD && mode&PLAY) o_mode=O_RDWR;
148         if((audio_fd=open_sound_dev(device,o_mode))==-1) {
149                 printf("unable to open %s\n",device);
150                 return -1;
151         }
152
153         /* file fd's */
154         if((mode&PLAY) || (mode&CONVERT)) {
155                 if((pfile_fd=open_file(play_file,O_RDONLY))==-1) {
156                         printf("unable to open file %s for reading\n",play_file);
157                         return -1;
158                 }
159         }
160         if((mode&RECORD) || (mode&CONVERT)) {
161                 if((sfile_fd=open_file(record_file,O_CREAT|O_WRONLY))==-1) {
162                         printf("unable to open file %s for writing\n",record_file);
163                         return -1;
164                 }
165         }
166
167         if(print_info) {
168                 if(mode&PLAY) {
169                         printf("file info:\n");
170                         lseek(pfile_fd,4,SEEK_SET);
171                         read(pfile_fd,&info_int,4);
172                         printf("file size: %d\n",info_int);
173                         lseek(pfile_fd,8,SEEK_CUR);
174                         read(pfile_fd,&info_int,4);
175                         printf("fmtsize: %d\n",info_int);
176                         if(info_int==16) set.format=AFMT_S16_LE;
177                         if(info_int==8) set.format=AFMT_U8;
178                         read(pfile_fd,&info_int,4);
179                         printf("format tag: %d\n",info_int&0xffff);
180                         printf("channels: %d\n",(info_int>>16)&0xffff);
181                         set.channel=(info_int>>16)&0xffff;
182                         read(pfile_fd,&info_int,4);
183                         printf("samples/sec: %d\n",info_int);
184                         set.freq=info_int;
185                         read(pfile_fd,&info_int,4);
186                         printf("bytes/sec: %d\n",info_int);
187                         read(pfile_fd,&info_int,4);
188                         printf("block allign: %d\n",info_int&0xffff);
189                         printf("bits/sample: %d\n",(info_int>>16)&0xffff);
190                         lseek(pfile_fd,4,SEEK_CUR);
191                         read(pfile_fd,&info_int,4);
192                         printf("datasize: %d\n\n",info_int);
193                         /* return to start */
194                         lseek(pfile_fd,0,SEEK_SET);
195                 }
196         }
197
198         /* set dsp and get capabilities */
199         if(get_dsp_cap(audio_fd,&set,1)==-1) {
200                 printf("unable to get capabilities :(\n");
201                 return -1;
202         }
203         if(set_dsp(audio_fd,&set)==-1) {
204                 printf("unable to set dsp :(\n");
205                 return -1;
206         }
207
208         /* allocating buffer */
209         if((buf=malloc(set.bufsize*sizeof(unsigned char)))==NULL) {
210                 printf("allocating memory failed :(\n");
211                 perror("malloc");
212                 return -1;
213         }
214
215         if((mode&RECORD) && (mode&PLAY)) {
216                 if((buf2=malloc(set.bufsize*sizeof(unsigned char)))==NULL) {
217                         printf("allocating 2nd memory failed :(\n");
218                         perror("malloc");
219                         return -1;
220                 }
221         }
222
223         if((mode&PLAY) && (!(mode&RECORD))) {
224
225         /* dfb */
226         DirectFBInit(&argc,&argv);
227         DirectFBCreate(&dfb);
228         dfb->SetCooperativeLevel(dfb,DFSCL_FULLSCREEN);
229         dsc.flags=DSDESC_CAPS;
230         dsc.caps=DSCAPS_PRIMARY|DSCAPS_FLIPPING;
231         dfb->CreateSurface(dfb,&dsc,&primary);
232         primary->GetSize(primary,&width,&height);
233         dprintf(1,"graphical equalizer dims: %dx%d\n",width,height);
234         primary->SetColor(primary,0x80,0x80,0xff,0xff);
235         //primary->Flip(primary,NULL,DSFLIP_WAITFORSYNC);
236
237         /* fourier */
238         fourier_init(&fourier,1);
239         fourier.type=FWD|DFT;
240         fourier.dim=1;
241         fourier.data_len[0]=set.bufsize/(set.format&AFMT_S16_LE?4:2);
242         fourier_alloc_data(&fourier);
243         printf("debug: allocated size for %d samples to do dft\n",fourier.data_len[0]);
244         dx=8*width/fourier.data_len[0];
245         printf("debug: dx = %d ???\n",dx);
246
247                 printf("playing file %s ...\n",play_file);
248                 if(mode&REVERSED) printf("but we do it reversed!\n");
249                 rw=1;
250                 if(!(mode&REVERSED)) {
251                         while(rw) {
252                                 /* read samples */
253                                 rw=read(pfile_fd,buf,set.bufsize);
254                                 /* do fourier trafo */
255                                 for(sample=0;sample<fourier.data_len[0];sample++) fourier.data[sample].r=*((signed short *)buf+(set.format&AFMT_S16_LE?2:1)*sample);
256                                 fourier_dft_1d(&fourier);
257                                 /* print graph */
258                                 primary->Clear(primary,0,0,0,0xff);
259                                 a_f=dx*fourier.data_len[0]*440/set.freq;
260                                 primary->DrawLine(primary,a_f,height,a_f,0);
261                                 for(sample=0;sample<fourier.data_len[0]/8;sample++) primary->FillRectangle(primary,sample*dx,0,dx,height*sqrt(fourier.ftdata[sample].r*fourier.ftdata[sample].r+fourier.ftdata[sample].i*fourier.ftdata[sample].i)/0x7fff);
262                                 primary->Flip(primary,NULL,DSFLIP_WAITFORSYNC);
263                                 //fcount=0;
264
265                                 //}
266
267                                 write(audio_fd,buf,set.bufsize);
268                         }
269                 } else {
270                         i=0;
271                         read(pfile_fd,info,4);
272                         if(!strncmp(info,"RIFF",4)) {
273                                 is_wav=1;
274                                 printf("\nassuming wav file according to header ...\n");
275                                 i=44;
276                         }
277                         lseek(pfile_fd,0,SEEK_SET);
278                         tmp=lseek(pfile_fd,0,SEEK_END);
279                         // if(set.format==AFMT_U8) i=set.channel;
280                         // if(set.format==AFMT_S16_LE) i=set.channel*2;
281                         for(j=0;j<(tmp-i);j++) {
282                                 for(k=0;k<set.bufsize;k++) {
283                                         lseek(pfile_fd,tmp-(j+1)*set.bufsize+k,SEEK_SET);
284                                         read(pfile_fd,buf+k,1);
285                                 }
286                                 write(audio_fd,buf,set.bufsize);
287                         }
288                 }
289
290                 /* dfb release */
291                 primary->Release(primary);
292                 dfb->Release(dfb);
293
294         }
295
296         if((mode&RECORD) && (!(mode&PLAY))) {
297                 printf("recording to file %s ...\n",record_file);
298                 rw=1;
299                 while(rw) {
300                         rw=read(audio_fd,buf,set.bufsize);
301                         write(sfile_fd,buf,set.bufsize);
302                 }
303         }
304
305         if((mode&RECORD) && (mode&PLAY)) {
306                 FD_ZERO(&read_fds);
307                 FD_ZERO(&write_fds);
308                 /* read_fds */
309                 FD_SET(0,&read_fds);
310                 FD_SET(pfile_fd,&read_fds);
311                 FD_SET(audio_fd,&read_fds);
312                 /* write_fds */
313                 FD_SET(sfile_fd,&write_fds);
314                 FD_SET(audio_fd,&write_fds);
315                 while(c!='q') {
316                         fds_tv.tv_sec=0;
317                         fds_tv.tv_usec=1000;
318                         k=select(sfile_fd+1,&read_fds,&write_fds,NULL,&fds_tv);
319                         if(k==0) printf("itz zZzero :p\n");
320                         if(k) {
321                                 printf("returned after %ld usecs\n",1000-fds_tv.tv_usec);
322                                 if(FD_ISSET(0,&read_fds)) {
323                                         read(0,&c,1);
324                                 }
325                                 if(FD_ISSET(pfile_fd,&read_fds)) {
326                                         read(pfile_fd,buf2,set.bufsize);
327                                 }
328                                 if(FD_ISSET(audio_fd,&read_fds)) {
329                                         read(audio_fd,buf,set.bufsize);
330                                 }
331                                 if(FD_ISSET(sfile_fd,&write_fds)) {
332                                         write(sfile_fd,buf,set.bufsize);
333                                 }
334                                 if(FD_ISSET(audio_fd,&write_fds)) {
335                                         write(audio_fd,buf2,set.bufsize);
336                                 }
337                         }
338                 }
339         }
340
341         if(mode&CONVERT) {
342                 if((tmp=lseek(pfile_fd,0,SEEK_END))==-1) {
343                         printf("cannot determine filesize :(\n");
344                         perror("lseek");
345                         return -1;
346                 }
347                 lseek(pfile_fd,0,SEEK_SET);
348                 strcpy(info,"RIFF");
349                 write(sfile_fd,info,4);
350                 info_int=tmp+36;
351                 write(sfile_fd,&info_int,4);
352                 strcpy(info,"WAVEfmt ");
353                 write(sfile_fd,info,8);
354                 if(set.format==AFMT_S16_LE) info_int=16;
355                 if(set.format==AFMT_U8) info_int=8;
356                 write(sfile_fd,&info_int,4);
357                 info_int=set.channel<<16;
358                 info_int|=1;
359                 write(sfile_fd,&info_int,4);
360                 info_int=set.freq;
361                 write(sfile_fd,&info_int,4);
362                 info_int=set.freq*set.channel;
363                 if(set.format==AFMT_S16_LE) info_int*=2;
364                 write(sfile_fd,&info_int,4);
365                 info_int=(set.channel*8)<<16;
366                 info_int|=set.channel;
367                 write(sfile_fd,&info_int,4);
368                 strcpy(info,"data");
369                 write(sfile_fd,info,4);
370                 info_int=tmp;
371                 write(sfile_fd,&info_int,4);
372                 /* write data now ... */
373                 for(j=0;j<tmp/set.bufsize;j++) {
374                         i=read(pfile_fd,buf,set.bufsize);
375                         k=write(sfile_fd,buf,set.bufsize);
376                         printf("read %d, wrote %d\n",i,k);
377                 }
378                 printf("\ndone ...\n");
379         }
380                         
381         return 1;
382 }