This example demonstrates how to use Dr. Fred DePiero's classes to read
and write to/from files in the .wav format. All of
Dr. DePiero's classes needed to read/write .wav files
are included without comment. The program also demonstrates the use of
command line arguments.
1// driver.cpp
2// Example program that uses the WAV_IN and WAV_OUT classes
3// written by Dr. Fred DePiero.
4// t a y l o r@msoe.edu, 6-26-2002
5
6#include <iostream>
7
8#include "wav_in.h"
9#include "wav_out.h"
10
11int main(int argc, char** argv)
12{
13 if(argc!=3) {
14 std::cerr<<"Reads in a .wav file and writes it out.\n"
15 << " by Dr. Chris Taylor, t a y l o r@msoe.edu, 6-26-2002\n"
16 << " Makes use of utility code written by Dr. Fred DePiero\n\n"
17 << "Usage: " << argv[0] << " infilename.wav outfilename.wav\n";
18 } else {
19 WAV_IN infile(argv[1]);
20 double sampleRate = infile.get_sample_rate_hz();
21 unsigned int bitsPerSample = infile.get_bits_per_sample();
22 unsigned int channels = infile.get_num_channels();
23 WAV_OUT outfile(sampleRate, bitsPerSample, channels);
24 while(infile.more_data_available()) {
25 double data = infile.read_current_input();
26 // If this were a real application, you'd probably do something
27 // to the data here.
28 outfile.write_current_output(data);
29 }
30 outfile.save_wave_file(argv[2]);
31 }
32 return 0;
33}
1/******************* FILE : wav_in.h *********************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#ifndef INCLUDE_WAV_IN
19#define INCLUDE_WAV_IN
20
21class WAV_OUT;
22
23class WAV_IN
24{
25
26public:
27
28 WAV_IN(char *wav_file_name);
29 ~WAV_IN();
30
31 // routine for reading one sample from a (previously loaded) wave file
32 // returns current sample as a double
33 double read_current_input();
34
35 // determines end-of-file condition, returns 1==true if more data ready
36 int more_data_available();
37
38 // returns number of samples in file
39 long int get_num_samples();
40
41 // reports number of channels (1==mono, 2==stereo)
42 int get_num_channels();
43
44 // reports the number of bits in each sample
45 int get_bits_per_sample();
46
47 // reports sample rate in Hz
48 double get_sample_rate_hz();
49
50protected:
51
52 double fs_hz;
53 int bits_per_sample;
54 int num_ch;
55
56 double *g_wdata_in;
57 int g_num_isamp;
58 long int g_max_isamp;
59
60 friend WAV_OUT;
61};
62
63#endif
1/******************* FILE : wav_out.h *********************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#ifndef INCLUDE_WAV_OUT
19#define INCLUDE_WAV_OUT
20
21class WAV_IN;
22
23
24class WAV_OUT
25{
26
27public:
28
29 // create a new wav_out with given parameters
30 // note: soundcards typically support a limited range of values!
31 // hence the next constructor is safer: WAV_OUT(WAV_IN *wav);
32 WAV_OUT(double fs_hz,int bits_per_sample,int num_ch);
33
34 // create a wav_out with the same parameters as a given wav_in
35 WAV_OUT(WAV_IN *wav_in);
36
37 ~WAV_OUT();
38
39 // routine for writing one output sample
40 // samples are stored in a buffer, until save_wave_file() is called
41 // returns 0 on success
42 int write_current_output(double ooo);
43
44 // routine for saving a wave file.
45 // returns 0 on success, negative value on error
46 int save_wave_file(char *wav_file_name);
47
48protected:
49
50 double fs_hz;
51 int bits_per_sample;
52 int num_ch;
53
54 double *g_wdata_out;
55 int g_num_osamp;
56 long int g_max_osamp;
57
58 friend WAV_IN;
59};
60
61#endif
1/******************* FILE : wav_def.h ********************/
2
3
4
5/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
6
7 This software is provided on an as-is basis, it may be
8 distributed in an unlimited fashion without charge provided
9 that it is used for scholarly purposes - it is not for
10 commercial use or profit. This notice must remain unaltered.
11
12 Software by Dr Fred DePiero - CalPoly State University
13
14\******************** END OF NOTICE ************************/
15
16
17
18
19// header of wav file
20typedef struct{
21 char rID[4]; // 'RIFF'
22 long int rLen;
23
24 char wID[4]; // 'WAVE'
25
26 char fId[4]; // 'fmt '
27 long int pcm_header_len; // varies...
28 short int wFormatTag;
29 short int nChannels; // 1,2 for stereo data is (l,r) pairs
30 long int nSamplesPerSec;
31 long int nAvgBytesPerSec;
32 short int nBlockAlign;
33 short int nBitsPerSample;
34} WAV_HDR;
35
36
37// header of wav file
38typedef struct{
39 char dId[4]; // 'data' or 'fact'
40 long int dLen;
41// unsigned char *data;
42} CHUNK_HDR;
43
44
45
1/************************** FILE : f_ptch.h ***************************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#ifndef F_PTCH_HH
19#define F_PTCH_HH
20
21#include <string.h>
22#include <memory.h>
23
24#define PI (3.14159265359)
25
26#define bcopy(src,dest,sz) memcpy(dest,src,(size_t)sz)
27
28#endif
29
1/************************ FILE : ferr.h ***************************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#ifndef FERR_H
19#define FERR_H
20
21#define thret_gerr(n,s) { printf("%s (%d)\n",s,n); exit(n); }
22#define threx_gerr(n,s) { printf("%s (%d)\n",s,n); exit(n); }
23#define threv_gerr(n,s) { printf("%s (%d)\n",s,n); exit(n); }
24#define throw_gerr(n,s) { printf("%s (%d)\n",s,n); exit(n); }
25#define reton_gerr()
26#define revon_gerr()
27#define clear_gerr()
28#define print_gerr()
29#define catch_gerr() 0
30
31#endif
32
1/*************** FILE : wav_in.cpp *******************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#include <cstdio>
19#include <cstdlib>
20#include <cmath>
21
22#include "f_err.h"
23#include "f_ptch.h"
24
25#include "wav_def.h"
26#include "wav_in.h"
27
28
29
30
31
32
33/********************************************\
34\********************************************/
35long int WAV_IN::get_num_samples(){ return g_max_isamp; }
36
37/********************************************\
38\********************************************/
39int WAV_IN::get_num_channels(){ return num_ch; }
40
41/********************************************\
42\********************************************/
43int WAV_IN::get_bits_per_sample(){ return bits_per_sample; }
44
45/********************************************\
46\********************************************/
47double WAV_IN::get_sample_rate_hz(){ return fs_hz; }
48
49/********************************************\
50\********************************************/
51int WAV_IN::more_data_available()
52{
53 if(g_num_isamp>=g_max_isamp) return 0;
54
55 return 1;
56}
57
58
59
60/**********************************************************
61**********************************************************/
62double WAV_IN::read_current_input()
63{
64 if( (g_wdata_in==NULL) || (g_max_isamp<=0) || (g_num_isamp<0) )
65 {
66 printf("input file not ready (or not loaded)!!!\n");
67 exit(1);
68 }
69 if(g_num_isamp>=g_max_isamp)
70 {
71 printf("attempt to read past end of input buffer!\n");
72 exit(1);
73 }
74
75 return( g_wdata_in[g_num_isamp++] );
76}
77
78
79
80
81
82/********************************************\
83\********************************************/
84WAV_IN::WAV_IN(char *file_name)
85{
86 int i;
87 FILE *fw;
88 unsigned int wstat;
89 char obuff[80];
90
91 WAV_HDR *wav;
92 CHUNK_HDR *chk;
93 short int *uptr;
94 unsigned char *cptr;
95 int sflag;
96 long int rmore;
97
98 char *wbuff;
99 int wbuff_len;
100
101 // set defaults
102 g_wdata_in = NULL;
103 g_num_isamp = 0;
104 g_max_isamp = 0;
105
106 // allocate wav header
107 wav = new WAV_HDR;
108 chk = new CHUNK_HDR;
109 if(wav==NULL){ printf("cant new headers\n"); exit(-1); }
110 if(chk==NULL){ printf("cant new headers\n"); exit(-1); }
111
112 /* open wav file */
113 fw = fopen(file_name,"rb");
114 if(fw==NULL){ printf("cant open wav file\n"); exit(-1); }
115
116 /* read riff/wav header */
117 wstat = fread((void *)wav,sizeof(WAV_HDR),(size_t)1,fw);
118 if(wstat!=1){ printf("cant read wav\n"); exit(-1); }
119
120 // check format of header
121 for(i=0;i<4;i++) obuff[i] = wav->rID[i];
122 obuff[4] = 0;
123 if(strcmp(obuff,"RIFF")!=0){ printf("bad RIFF format\n"); exit(-1); }
124
125 for(i=0;i<4;i++) obuff[i] = wav->wID[i];
126 obuff[4] = 0;
127 if(strcmp(obuff,"WAVE")!=0){ printf("bad WAVE format\n"); exit(-1); }
128
129 for(i=0;i<3;i++) obuff[i] = wav->fId[i];
130 obuff[3] = 0;
131 if(strcmp(obuff,"fmt")!=0){ printf("bad fmt format\n"); exit(-1); }
132
133 if(wav->wFormatTag!=1){ printf("bad wav wFormatTag\n"); exit(-1); }
134
135 if( (wav->nBitsPerSample != 16) && (wav->nBitsPerSample != 8) ){
136 printf("bad wav nBitsPerSample\n"); exit(-1); }
137
138
139 // skip over any remaining portion of wav header
140 rmore = wav->pcm_header_len - (sizeof(WAV_HDR) - 20);
141 wstat = fseek(fw,rmore,SEEK_CUR);
142 if(wstat!=0){ printf("cant seek\n"); exit(-1); }
143
144
145 // read chunks until a 'data' chunk is found
146 sflag = 1;
147 while(sflag!=0){
148
149 // check attempts
150 if(sflag>10){ printf("too many chunks\n"); exit(-1); }
151
152 // read chunk header
153 wstat = fread((void *)chk,sizeof(CHUNK_HDR),(size_t)1,fw);
154 if(wstat!=1){ printf("cant read chunk\n"); exit(-1); }
155
156 // check chunk type
157 for(i=0;i<4;i++) obuff[i] = chk->dId[i];
158 obuff[4] = 0;
159 if(strcmp(obuff,"data")==0) break;
160
161 // skip over chunk
162 sflag++;
163 wstat = fseek(fw,chk->dLen,SEEK_CUR);
164 if(wstat!=0){ printf("cant seek\n"); exit(-1); }
165 }
166
167 /* find length of remaining data */
168 wbuff_len = chk->dLen;
169
170 // find number of samples
171 g_max_isamp = chk->dLen;
172 g_max_isamp /= wav->nBitsPerSample / 8;
173
174 /* allocate new buffers */
175 wbuff = new char [wbuff_len];
176 if(wbuff==NULL){ printf("cant alloc\n"); exit(-1); }
177
178// if(g_wdata_in!=NULL) delete g_wdata_in;
179 g_wdata_in = new double [g_max_isamp];
180 if(g_wdata_in==NULL){ printf("cant alloc\n"); exit(-1); }
181
182
183 /* read signal data */
184 wstat = fread((void *)wbuff,wbuff_len,(size_t)1,fw);
185 if(wstat!=1){ printf("cant read wbuff\n"); exit(-1); }
186
187 // convert data
188 if(wav->nBitsPerSample == 16){
189 uptr = (short *) wbuff;
190 for(i=0;i<g_max_isamp;i++) g_wdata_in[i] = (double) (uptr[i]);
191 }
192 else{
193 cptr = (unsigned char *) wbuff;
194 for(i=0;i<g_max_isamp;i++) g_wdata_in[i] = (double) (cptr[i]);
195 }
196
197 // save demographics
198 fs_hz = (double) (wav->nSamplesPerSec);
199 bits_per_sample = wav->nBitsPerSample;
200 num_ch = wav->nChannels;
201
202 printf("\nLoaded WAV File: %s\n",file_name);
203 printf(" Sample Rate = %1.0lf (Hz)\n",fs_hz);
204 printf(" Number of Samples = %ld\n",g_max_isamp);
205 printf(" Bits Per Sample = %d\n",bits_per_sample);
206 printf(" Number of Channels = %d\n\n",num_ch);
207
208 // reset buffer stream index
209 g_num_isamp = 0;
210
211 // be polite - clean up
212 if(wbuff!=NULL) delete wbuff;
213 if(wav!=NULL) delete wav;
214 if(chk!=NULL) delete chk;
215 fclose(fw);
216
217 return;
218
219/* WAV_IN::WAV_IN() */}
220
221
222
223
224
225
226/********************************************\
227\********************************************/
228WAV_IN::~WAV_IN(){ }
229
230
231
232
1/******************* FILE : wav_out.cpp ********************/
2
3
4/****** NOTICE: LIMITATIONS ON USE AND DISTRIBUTION ********\
5
6 This software is provided on an as-is basis, it may be
7 distributed in an unlimited fashion without charge provided
8 that it is used for scholarly purposes - it is not for
9 commercial use or profit. This notice must remain unaltered.
10
11 Software by Dr Fred DePiero - CalPoly State University
12
13\******************** END OF NOTICE ************************/
14
15
16
17
18#include <cstdio>
19#include <cstdlib>
20#include <cmath>
21
22#include "f_err.h"
23#include "f_ptch.h"
24
25#include "wav_def.h"
26#include "wav_out.h"
27#include "wav_in.h"
28
29
30
31
32
33/**********************************************************
34**********************************************************/
35int WAV_OUT::write_current_output(double ooo)
36{
37 int i;
38 double *tmp = NULL;
39
40 // alloc initial buffer
41 if(g_wdata_out==NULL)
42 {
43 g_max_osamp = 1024;
44
45 g_wdata_out = new double [g_max_osamp];
46 for(i=0;i<g_num_osamp;i++) g_wdata_out[i] = 0.0;
47
48 if(g_wdata_out==NULL){ printf("cant alloc in WAV_OUT\n"); exit(-1); }
49 }
50
51 // enlarge buffer
52 if(g_num_osamp>=g_max_osamp)
53 {
54 g_max_osamp *= 2;
55 tmp = new double [g_max_osamp];
56 if(tmp==NULL){ printf("cant realloc in WAV_OUT\n"); exit(-1); }
57
58 // copy over
59 for(i=0;i<g_num_osamp;i++) tmp[i] = g_wdata_out[i];
60 for(i=g_num_osamp;i<g_max_osamp;i++) tmp[i] = 0.0;
61
62 // swap buffers
63 delete g_wdata_out;
64 g_wdata_out = tmp;
65 }
66
67 // buffer input data
68 g_wdata_out[g_num_osamp++] = ooo;
69
70 // be polite
71 return 0;
72
73/* int WAV_OUT::write(double ooo) */}
74
75
76
77
78
79
80/**********************************************************
81**********************************************************/
82int WAV_OUT::save_wave_file(char *fname)
83{
84 FILE *fw;
85 unsigned int wstat;
86 int i;
87 char obuff[80];
88
89 WAV_HDR *wav;
90 CHUNK_HDR *chk;
91 char *wbuff;
92 int wbuff_len;
93
94 short int *uptr;
95 double ttt;
96 double max_uuu = (65536.0 / 2.0) - 1.0;
97 double min_uuu = -(65536.0 / 2.0);
98
99 unsigned char *cptr;
100 double max_ccc = 256.0;
101 double min_ccc = 0.0;
102
103 if(g_num_osamp<=0) printf("warning, no new data written to output\n");
104
105 // allocate wav header
106 wav = new WAV_HDR;
107 chk = new CHUNK_HDR;
108 if(wav==NULL){ printf("cant new headers\n"); exit(-1); }
109 if(chk==NULL){ printf("cant new headers\n"); exit(-1); }
110
111 /* allocate new data buffers */
112 wbuff_len = g_num_osamp * bits_per_sample / 8;
113 wbuff = new char [wbuff_len];
114 if(wbuff==NULL){ printf("cant alloc\n"); exit(-1); }
115
116 // setup wav header
117 sprintf(obuff,"RIFF");
118 for(i=0;i<4;i++) wav->rID[i] = obuff[i];
119
120 sprintf(obuff,"WAVE");
121 for(i=0;i<4;i++) wav->wID[i] = obuff[i];
122
123 sprintf(obuff,"fmt ");
124 for(i=0;i<4;i++) wav->fId[i] = obuff[i];
125
126 wav->nBitsPerSample = bits_per_sample;
127 wav->nSamplesPerSec = (int) fs_hz;
128 wav->nAvgBytesPerSec = (int) fs_hz;
129 wav->nAvgBytesPerSec *= bits_per_sample / 8;
130 wav->nAvgBytesPerSec *= num_ch;
131 wav->nChannels = num_ch;
132
133 wav->pcm_header_len = 16;
134 wav->wFormatTag = 1;
135 wav->rLen = sizeof(WAV_HDR) + sizeof(CHUNK_HDR) + wbuff_len;
136 wav->nBlockAlign = num_ch * bits_per_sample / 8;
137
138
139 // setup chunk header
140 sprintf(obuff,"data");
141 for(i=0;i<4;i++) chk->dId[i] = obuff[i];
142
143 chk->dLen = wbuff_len;
144
145
146 // convert data
147 if(bits_per_sample == 16){
148 uptr = (short *) wbuff;
149 for(i=0;i<g_num_osamp;i++){
150 ttt = g_wdata_out[i];
151 if(ttt>max_uuu) ttt = max_uuu;
152 if(ttt<min_uuu) ttt = min_uuu;
153 uptr[i] = (short int) ttt;
154 }
155 }
156 else if(bits_per_sample == 8){
157 cptr = (unsigned char *) wbuff;
158 for(i=0;i<g_num_osamp;i++){
159 ttt = g_wdata_out[i];
160 if(ttt>max_ccc) ttt = max_ccc;
161 if(ttt<min_ccc) ttt = min_ccc;
162 cptr[i] = (unsigned char) ttt;
163 }
164 }
165 else{ printf("bunk bits_per_sample\n"); exit(-1); }
166
167
168 /* open wav file */
169 fw = fopen(fname,"wb");
170 if(fw==NULL){ printf("cant open wav file\n"); exit(-1); }
171
172
173 /* write riff/wav header */
174 wstat = fwrite((void *)wav,sizeof(WAV_HDR),(size_t)1,fw);
175 if(wstat!=1){ printf("cant write wav\n"); exit(-1); }
176
177 /* write chunk header */
178 wstat = fwrite((void *)chk,sizeof(CHUNK_HDR),(size_t)1,fw);
179 if(wstat!=1){ printf("cant write chk\n"); exit(-1); }
180
181 /* write data */
182 wstat = fwrite((void *)wbuff,wbuff_len,(size_t)1,fw);
183 if(wstat!=1){ printf("cant write wbuff\n"); exit(-1); }
184
185
186 printf("\nSaved WAV File: %s\n",fname);
187 printf(" Sample Rate = %1.0lf (Hz)\n",fs_hz);
188 printf(" Number of Samples = %ld\n",g_num_osamp);
189 printf(" Bits Per Sample = %d\n",bits_per_sample);
190 printf(" Number of Channels = %d\n\n",num_ch);
191
192
193 // reset output stream index
194 g_num_osamp = 0;
195
196 // be polite
197 if(wbuff!=NULL) delete wbuff;
198 if(wav!=NULL) delete wav;
199 if(chk!=NULL) delete chk;
200 fclose(fw);
201 return 0;
202
203/* int WAV_OUT::save_wave_file(char *fname) */}
204
205
206
207
208
209/********************************************\
210\********************************************/
211WAV_OUT::WAV_OUT(double _fs_hz,int _bits_per_sample,int _num_ch)
212{
213
214 fs_hz = _fs_hz;
215 bits_per_sample = _bits_per_sample;
216 num_ch = _num_ch;
217
218 g_wdata_out = NULL;
219 g_num_osamp = 0;
220 g_max_osamp = 0;
221
222 return;
223
224/* WAV_OUT::WAV_OUT(,,,) */}
225
226
227
228
229
230/********************************************\
231\********************************************/
232WAV_OUT::WAV_OUT(WAV_IN *wav_in)
233{
234
235 fs_hz = wav_in->fs_hz;
236 bits_per_sample = wav_in->bits_per_sample;
237 num_ch = wav_in->num_ch;
238
239 g_wdata_out = NULL;
240 g_num_osamp = 0;
241 g_max_osamp = 0;
242
243 return;
244
245/* WAV_OUT::WAV_OUT(,,,) */}
246
247
248
249
250
251
252
253/********************************************\
254\********************************************/
255WAV_OUT::~WAV_OUT(){ }
256
257
258
259