1 /* wavgen - Generate a test wave file for testing wavbreaker
2  * Copyright (C) 2015 Thomas Perl <m@thp.io>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include <glib.h>
24 
25 
26 #ifndef M_PI
27 #define M_PI (3.14159265358979323846)
28 #endif
29 
30 
31 #include "wav.h"
32 #include "sample.h"
33 
34 
35 typedef void (*ampfreq_func_t)(float, float *, float *);
36 
37 static inline void
ampfreq1(float pos,float * amp,float * freq)38 ampfreq1(float pos, float *amp, float *freq)
39 {
40     pos *= 2 * M_PI;
41     *amp = fabsf(cosf(pos * 13.f));
42     *freq = 440.f + 440.f * sinf(pos * 77.f);
43 }
44 
45 typedef void (*generate_audio_func_t)(FILE *, SampleInfo *, void *);
46 
47 static void
generate_ampfreq(FILE * fp,SampleInfo * si,void * user_data)48 generate_ampfreq(FILE *fp, SampleInfo *si, void *user_data)
49 {
50     ampfreq_func_t f = (ampfreq_func_t)user_data;
51 
52     int samples = si->numBytes / si->channels;
53     int i;
54     for (i=0; i<samples; i++) {
55         float pos = (float)i / samples;
56         float amp, freq;
57 
58         f(pos, &amp, &freq);
59 
60         amp *= sinf(freq * M_PI * (float)i / (si->samplesPerSec));
61 
62         int ch;
63         for (ch=0; ch<si->channels; ch++) {
64             if (si->bitsPerSample == 8) {
65                 char buf = 127 + 127 * amp;
66                 fwrite(&buf, sizeof(buf), 1, fp);
67             } else if (si->bitsPerSample == 16) {
68                 short buf = amp * 0x7fff;
69                 fwrite(&buf, sizeof(buf), 1, fp);
70             }
71         }
72     }
73 }
74 
75 typedef char (*oneliner_func_t)(int t);
76 
77 // http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html
oneliner(int t)78 static char oneliner(int t) { return t*(((t>>12)|(t>>8))&(63&(t>>4))); }
79 
80 static void
generate_oneliner(FILE * fp,SampleInfo * si,void * user_data)81 generate_oneliner(FILE *fp, SampleInfo *si, void *user_data)
82 {
83     g_assert_cmpint(si->channels, ==, 1);
84     g_assert_cmpint(si->bitsPerSample, ==, 8);
85     g_assert_cmpint(si->samplesPerSec, ==, 8000);
86 
87     oneliner_func_t f = (oneliner_func_t)user_data;
88 
89     int t;
90     for (t=0; t<si->numBytes; t++) {
91         fputc(f(t), fp);
92     }
93 }
94 
95 int
main(int argc,char * argv[])96 main(int argc, char *argv[])
97 {
98     struct {
99         char *name;
100         int channels;
101         int samplesPerSec;
102         int bitsPerSample;
103         int seconds;
104         generate_audio_func_t generate_func;
105         void *generate_func_user_data;
106     } templates[] = {
107         { "gen", 2, 44100, 16, 60, generate_ampfreq, &ampfreq1 },
108         { "gen", 2, 44100, 8, 60, generate_ampfreq, &ampfreq1 },
109         { "gen", 1, 44100, 16, 60, generate_ampfreq, &ampfreq1 },
110         { "gen", 1, 44100, 8, 60, generate_ampfreq, &ampfreq1 },
111         { "gen", 1, 22050, 8, 60, generate_ampfreq, &ampfreq1 },
112         { "gen", 1, 11025, 8, 60, generate_ampfreq, &ampfreq1 },
113         { "oneliner", 1, 8000, 8, 60, generate_oneliner, &oneliner },
114         { "gen_long", 2, 44100, 16, 60 * 3, generate_ampfreq, &ampfreq1 },
115     };
116 
117     int i;
118 
119     for (i=0; i<sizeof(templates)/sizeof(templates[0]); i++) {
120         SampleInfo si;
121         memset(&si, 0, sizeof(si));
122 
123         si.channels = templates[i].channels;
124         si.samplesPerSec = templates[i].samplesPerSec;
125         si.bitsPerSample = templates[i].bitsPerSample;
126 
127         si.blockAlign = si.channels * (si.bitsPerSample / 8);
128         si.avgBytesPerSec = si.blockAlign * si.samplesPerSec;
129 
130         si.numBytes = si.avgBytesPerSec * templates[i].seconds;
131 
132         si.bufferSize = DEFAULT_BUF_SIZE; // unused here, just for playback
133         si.blockSize = si.avgBytesPerSec / CD_BLOCKS_PER_SEC; // unused here, just for playback
134 
135         char *filename = g_strdup_printf("wav_%s_%dch_%dhz_%dbit.wav", templates[i].name,
136                 si.channels, si.samplesPerSec, si.bitsPerSample);
137 
138         printf("%s ... ", filename);
139         fflush(stdout);
140 
141         if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
142             printf("EXISTS\n");
143         } else {
144             FILE *fp = fopen(filename, "wb");
145             if (fp) {
146                 wav_write_file_header(fp, &si, si.numBytes);
147                 templates[i].generate_func(fp, &si, templates[i].generate_func_user_data);
148                 fclose(fp);
149                 printf("OK\n");
150             } else {
151                 printf("FAIL\n");
152             }
153         }
154 
155         g_free(filename);
156     }
157 
158     return 0;
159 }
160