1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 2010 Unavowed <unavowed@vexillium.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include <assert.h>
21 #include <limits.h>
22 #include <string.h>
23 #include <stdlib.h>
24 
25 #include <ALL.h>
26 #include <dbglog.h>
27 #include <file_input_stream.h>
28 #include <file_util.h>
29 #include <wav_stream.h>
30 
31 DBGLOG_DEFAULT_CHANNEL(Audio);
32 
33 struct FormatHeader
34 {
35    enum { SIZE = 16 };
36 
37    uint16_t audio_format;
38    uint16_t num_channels;
39    uint32_t frame_rate;
40    uint32_t byte_rate;
41    uint16_t block_align;
42    uint16_t bits_per_sample;
43 };
44 
read_format_header(InputStream * in,FormatHeader * hdrp)45 static bool read_format_header(InputStream *in, FormatHeader *hdrp)
46 {
47    bool ok = true;
48 
49    ok = ok && read_le<uint16_t>(in, &hdrp->audio_format);
50    ok = ok && read_le<uint16_t>(in, &hdrp->num_channels);
51    ok = ok && read_le<uint32_t>(in, &hdrp->frame_rate);
52    ok = ok && read_le<uint32_t>(in, &hdrp->byte_rate);
53    ok = ok && read_le<uint16_t>(in, &hdrp->block_align);
54    ok = ok && read_le<uint16_t>(in, &hdrp->bits_per_sample);
55 
56    return ok;
57 }
58 
59 
WavStream()60 WavStream::WavStream()
61 {
62    this->clear();
63 }
64 
~WavStream()65 WavStream::~WavStream()
66 {
67    this->close();
68 }
69 
clear()70 void WavStream::clear()
71 {
72    this->in = NULL;
73    this->data_offset = 0;
74    this->data_length = 0;
75    this->data_left = 0;
76    this->fram_rate = 0;
77    this->chans = 0;
78    this->bytes = 0;
79    this->good = true;
80 }
81 
advance_to_chunk(const char * name,uint32_t * sizep)82 bool WavStream::advance_to_chunk(const char *name, uint32_t *sizep)
83 {
84    char buffer[4];
85    uint32_t size;
86    bool ok = true;
87 
88    for (;;)
89    {
90       ok = ok && in->read(buffer, 4);
91       ok = ok && read_le<uint32_t>(this->in, &size);
92 
93       if (!ok)
94 	 return false;
95 
96       if (memcmp(buffer, name, 4) == 0)
97       {
98 	 *sizep = size;
99 	 return true;
100       }
101 
102       ok = ok && this->in->seek(size, SEEK_CUR);
103    }
104 
105    return false;
106 }
107 
open(const char * file_name)108 bool WavStream::open(const char *file_name)
109 {
110    FileInputStream *in;
111 
112    this->close();
113 
114    in = new FileInputStream;
115    if (!in->open(file_name) || !this->open(in))
116    {
117       delete in;
118       return false;
119    }
120 
121    return true;
122 }
123 
open(InputStream * in)124 bool WavStream::open(InputStream *in)
125 {
126    char name[4];
127    uint32_t size;
128    bool ok = true;
129    FormatHeader fmth;
130 
131    this->close();
132    this->in = in;
133 
134    ok = ok && this->in->seek(0, SEEK_SET);
135    ok = ok && in->read(name, 4);
136    ok = ok && (memcmp(name, "RIFF", 4) == 0);
137    ok = ok && this->in->seek(4, SEEK_CUR);
138    ok = ok && in->read(name, 4);
139    ok = ok && (memcmp(name, "WAVE", 4) == 0);
140 
141    if (!ok)
142    {
143       ERR("[WavStream::open] Not a wave file\n");
144       goto err;
145    }
146 
147    ok = ok && this->advance_to_chunk("fmt ", &size);
148    ok = ok && (size >= FormatHeader::SIZE);
149    ok = ok && read_format_header(this->in, &fmth);
150    ok = ok && this->in->seek(size - FormatHeader::SIZE, SEEK_CUR);
151    if (!ok || fmth.audio_format != 1
152        || (fmth.bits_per_sample != 8 && fmth.bits_per_sample != 16)
153        || (fmth.num_channels != 1 && fmth.num_channels != 2))
154    {
155       ERR("[WavStream::open] Unsupported format\n");
156       goto err;
157    }
158 
159    this->bytes = fmth.bits_per_sample / 8;
160    this->chans = fmth.num_channels;
161    this->fram_rate = fmth.frame_rate;
162 
163    ok = ok && this->advance_to_chunk("data", &size);
164    if (!ok)
165    {
166       ERR("[WavStream::open] Missing data chunk\n");
167       goto err;
168    }
169 
170    this->data_offset = this->in->tell();
171    this->data_length = size / this->frame_size();
172    this->data_left = this->data_length;
173 
174    return true;
175 
176 err:
177    this->in = NULL; /* do not close in on error */
178    this->close();
179    return false;
180 }
181 
seek(size_t frame_no)182 bool WavStream::seek(size_t frame_no)
183 {
184    if (!this->good)
185       return false;
186 
187    if (frame_no >= this->data_length)
188       return false;
189 
190    if (!this->in->seek(this->data_offset + this->frame_size() * frame_no,
191 		       SEEK_SET))
192    {
193       ERR("[WavStream::seek] Seek failed\n");
194       this->good = false;
195       return false;
196    }
197 
198    this->data_left = this->data_length - frame_no;
199 
200    return true;
201 }
202 
close()203 void WavStream::close()
204 {
205    delete this->in;
206    this->clear();
207 }
208 
read(void * buffer,size_t frame_count)209 long WavStream::read(void *buffer, size_t frame_count)
210 {
211    size_t read_size;
212 
213    if (!this->good)
214       return -1;
215 
216    read_size = MIN(frame_count, this->data_left);
217    if (read_size == 0)
218       return 0;
219 
220    if (this->bytes == 2)
221    {
222       int16_t *buf = static_cast<int16_t *>(buffer);
223       int16_t *p;
224 
225       for (size_t n = 0; n < read_size; n++)
226       {
227 	 for (int c = 0; c < this->chans; c++)
228 	 {
229 	    p = &buf[n * this->chans + c];
230 
231 	    if (!read_le<int16_t>(this->in, p))
232 	    {
233 	       this->good = false;
234 	       return n;
235 	    }
236 	 }
237       }
238    }
239    else if (this->bytes == 1)
240    {
241       if (!this->in->read(buffer, this->chans * read_size))
242       {
243 	 this->good = false;
244 	 return 0;
245       }
246    }
247    else
248       abort();
249 
250    this->data_left -= read_size;
251 
252    return read_size;
253 }
254 
frame_rate() const255 int32_t WavStream::frame_rate() const
256 {
257    return this->fram_rate;
258 }
259 
channels() const260 int WavStream::channels() const
261 {
262    return this->chans;
263 }
264 
sample_size() const265 int WavStream::sample_size() const
266 {
267    return this->bytes;
268 }
269