Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / io / gr_wavfile_source.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2008 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_wavfile_source.h>
28 #include <gr_io_signature.h>
29 #include <gri_wavfile.h>
30 #include <cstdio>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <stdexcept>
34
35 // win32 (mingw/msvc) specific
36 #ifdef HAVE_IO_H
37 #include <io.h>
38 #endif
39 #ifdef O_BINARY
40 #define OUR_O_BINARY O_BINARY
41 #else
42 #define OUR_O_BINARY 0
43 #endif
44 // should be handled via configure
45 #ifdef O_LARGEFILE
46 #define OUR_O_LARGEFILE O_LARGEFILE
47 #else
48 #define OUR_O_LARGEFILE 0
49 #endif
50
51
52 gr_wavfile_source_sptr
53 gr_make_wavfile_source (const char *filename, bool repeat)
54 {
55   return gr_wavfile_source_sptr (new gr_wavfile_source (filename, repeat));
56 }
57
58
59 gr_wavfile_source::gr_wavfile_source (const char *filename, bool repeat)
60   : gr_sync_block ("wavfile_source",
61                    gr_make_io_signature (0, 0, 0),
62                    gr_make_io_signature (1, 2, sizeof(float))),
63     d_fp(NULL), d_repeat(repeat),
64     d_sample_rate(1), d_nchans(1), d_bytes_per_sample(2), d_first_sample_pos(0),
65     d_samples_per_chan(0), d_sample_idx(0)
66 {
67   // we use "open" to use to the O_LARGEFILE flag
68
69   int fd;
70   if ((fd = open (filename, O_RDONLY | OUR_O_LARGEFILE | OUR_O_BINARY)) < 0) {
71     perror (filename);
72     throw std::runtime_error ("can't open file");
73   }
74
75   if ((d_fp = fdopen (fd, "rb")) == NULL) {
76     perror (filename);
77     throw std::runtime_error ("can't open file");
78   }
79
80   // Scan headers, check file validity
81   if (!gri_wavheader_parse(d_fp,
82                            d_sample_rate,
83                            d_nchans,
84                            d_bytes_per_sample,
85                            d_first_sample_pos,
86                            d_samples_per_chan)) {
87     throw std::runtime_error("is not a valid wav file");
88   }
89   
90   if (d_samples_per_chan == 0) {
91     throw std::runtime_error("WAV file does not contain any samples");
92   }
93
94   if (d_bytes_per_sample == 1) {
95     d_normalize_fac   = 128;
96     d_normalize_shift = 1;
97   } else {
98     d_normalize_fac   = 0x7FFF;
99     d_normalize_shift = 0;
100   }
101
102   // Re-set the output signature
103   set_output_signature(gr_make_io_signature(1, d_nchans, sizeof(float)));
104 }
105
106
107 gr_wavfile_source::~gr_wavfile_source ()
108 {
109   fclose(d_fp);
110 }
111
112
113 int
114 gr_wavfile_source::work(int noutput_items,
115                         gr_vector_const_void_star &input_items,
116                         gr_vector_void_star &output_items)
117 {
118   float **out = (float **) &output_items[0];
119   int n_out_chans = output_items.size();
120
121   int i;
122   short sample;
123
124   for (i = 0; i < noutput_items; i++) {
125     if (d_sample_idx >= d_samples_per_chan) {
126       if (!d_repeat) {
127         // if nothing was read at all, say we're done.
128         return i ? i : -1;
129       }
130
131       if (fseek (d_fp, d_first_sample_pos, SEEK_SET) == -1) {
132         fprintf(stderr, "[%s] fseek failed\n", __FILE__);
133         exit(-1);
134       }
135
136       d_sample_idx = 0;
137     }
138     
139     for (int chan = 0; chan < d_nchans; chan++) {
140       sample = gri_wav_read_sample(d_fp, d_bytes_per_sample);
141
142       if (chan < n_out_chans) {
143         out[chan][i] = convert_to_float(sample);
144       }
145     }
146
147     d_sample_idx++;
148     
149     // OK, EOF is not necessarily an error. But we're not going to
150     // deal with handling corrupt wav files, so if they give us any
151     // trouble they won't be processed. Serves them bloody right.
152     if (feof(d_fp) || ferror(d_fp)) {
153       if (i == 0) {
154         fprintf(stderr, "[%s] WAV file has corrupted header or i/o error\n", __FILE__);
155         return -1;
156       }
157       return i;
158     }
159   }
160   
161   return noutput_items;
162 }
163
164
165 float
166 gr_wavfile_source::convert_to_float(short int sample)
167 {
168   float sample_out = (float) sample;
169   sample_out /= d_normalize_fac;
170   sample_out -= d_normalize_shift;
171   return sample_out;
172 }