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, &, &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, &freq1 },
108 { "gen", 2, 44100, 8, 60, generate_ampfreq, &freq1 },
109 { "gen", 1, 44100, 16, 60, generate_ampfreq, &freq1 },
110 { "gen", 1, 44100, 8, 60, generate_ampfreq, &freq1 },
111 { "gen", 1, 22050, 8, 60, generate_ampfreq, &freq1 },
112 { "gen", 1, 11025, 8, 60, generate_ampfreq, &freq1 },
113 { "oneliner", 1, 8000, 8, 60, generate_oneliner, &oneliner },
114 { "gen_long", 2, 44100, 16, 60 * 3, generate_ampfreq, &freq1 },
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