1
// ------------------------------------------------------------------------
2
// audioio-wave.cpp: RIFF WAVE audio file input/output.
3
// Copyright (C) 1999-2003,2005,2008,2009 Kai Vehmanen
6
// eca-style-version: 3
9
// - http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
11
// This program is free software; you can redistribute it and/or modify
12
// it under the terms of the GNU General Public License as published by
13
// the Free Software Foundation; either version 2 of the License, or
14
// (at your option) any later version.
16
// This program is distributed in the hope that it will be useful,
17
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
// GNU General Public License for more details.
21
// You should have received a copy of the GNU General Public License
22
// along with this program; if not, write to the Free Software
23
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
// ------------------------------------------------------------------------
34
#ifdef HAVE_SYS_TYPES_H
35
#include <sys/types.h> /* off_t */
38
#include <kvu_message_item.h>
39
#include <kvu_numtostr.h>
42
#include "sample-specs.h" /* for system endianess */
43
#include "samplebuffer.h"
44
#include "audioio-wave.h"
46
#include "eca-fileio-mmap.h"
47
#include "eca-fileio-stream.h"
49
#include "eca-logger.h"
52
* Private macro definitions
56
#define UINT32_MAX 4294967295U
59
#ifdef WORDS_BIGENDIAN
60
static const bool is_system_littleendian = false;
62
static const bool is_system_littleendian = true;
66
* Private function declarations
69
static uint16_t little_endian_uint16(uint16_t arg);
70
static uint32_t little_endian_uint32(uint32_t arg);
73
* Private function definitions
76
static uint16_t little_endian_uint16(uint16_t arg)
78
if (is_system_littleendian != true) {
79
return ((arg >> 8) & 0x00ff) | ((arg << 8) & 0xff00);
84
static uint32_t little_endian_uint32(uint32_t arg)
86
if (is_system_littleendian != true) {
87
return ((arg >> 24) & 0x000000ff) |
88
((arg >> 8) & 0x0000ff00) |
89
((arg << 8) & 0x00ff0000) |
90
((arg << 24) & 0xff000000);
100
* Print extra debug information about RIFF header
101
* contents to stdout when opening files.
103
// #define DEBUG_WAVE_HEADER
105
WAVEFILE::WAVEFILE (const std::string& name)
109
mmaptoggle_rep = "0";
112
WAVEFILE::~WAVEFILE(void)
114
if (is_open() == true) {
119
WAVEFILE* WAVEFILE::clone(void) const
121
WAVEFILE* target = new WAVEFILE();
122
for(int n = 0; n < number_of_params(); n++) {
123
target->set_parameter(n + 1, get_parameter(n + 1));
128
void WAVEFILE::format_query(void) throw(AUDIO_IO::SETUP_ERROR&)
131
DBC_REQUIRE(is_open() != true);
134
if (io_mode() == io_write) return;
136
fio_repp = new ECA_FILE_IO_STREAM();
138
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for reading."));
140
fio_repp->open_file(label(), "rb");
141
if (fio_repp->file_mode() != "") {
142
set_length_in_bytes();
143
read_riff_fmt(); // also sets format()
144
find_riff_datablock();
145
fio_repp->close_file();
151
DBC_ENSURE(!is_open());
152
DBC_ENSURE(fio_repp == 0);
156
void WAVEFILE::open(void) throw (AUDIO_IO::SETUP_ERROR &)
161
if (mmaptoggle_rep == "1") {
162
ECA_LOG_MSG(ECA_LOGGER::user_objects, "using mmap() mode for file access");
163
fio_repp = new ECA_FILE_IO_MMAP();
165
else fio_repp = new ECA_FILE_IO_STREAM();
167
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for reading."));
169
fio_repp->open_file(label(), "rb");
170
if (fio_repp->is_file_ready() != true) {
171
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Couldn't open file \"" + label() + "\" for reading."));
174
read_riff_fmt(); // also sets format()
175
set_length_in_bytes();
176
find_riff_datablock();
181
fio_repp = new ECA_FILE_IO_STREAM();
183
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for writing."));
185
fio_repp->open_file(label(), "w+b");
186
if (fio_repp->is_file_ready() != true) {
187
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Couldn't open file \"" + label() + "\" for writing."));
191
write_riff_datablock();
197
fio_repp = new ECA_FILE_IO_STREAM();
199
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for read&write."));
201
fio_repp->open_file(label(), "r+b");
202
if (fio_repp->file_mode() != "") {
203
set_length_in_bytes();
204
read_riff_fmt(); // also sets format()
205
find_riff_datablock();
208
fio_repp->open_file(label(), "w+b");
209
if (fio_repp->is_file_ready() != true)
210
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Couldn't open file \"" + label() + "\" for read&write."));
214
write_riff_datablock();
216
if (fio_repp->is_file_ready() != true) {
217
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Couldn't open file \"" + label() + "\" for read&write."));
223
if (little_endian_uint16(riff_format_rep.bits) > 8 &&
224
format_string()[0] == 'u')
225
throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: unsigned sample format accepted only with 8bit."));
227
if (little_endian_uint16(riff_format_rep.bits) > 8 &&
228
format_string().size() > 4 &&
229
format_string()[4] == 'b') {
230
/* force little-endian operation / affects only write-mode */
231
set_sample_format_string(format_string()[0] + kvu_numtostr(bits()) + "_le");
232
ECA_LOG_MSG(ECA_LOGGER::user_objects, "forcing little-endian operation (" + format_string() + ")");
233
DBC_CHECK(format_string().size() > 4 && format_string()[4] != 'b');
239
void WAVEFILE::close(void)
241
ECA_LOG_MSG(ECA_LOGGER::user_objects,"Closing file " + label());
242
if (is_open() == true && fio_repp != 0) {
244
fio_repp->close_file();
252
void WAVEFILE::update (void)
254
if (io_mode() != io_read) {
255
update_riff_datablock();
257
set_length_in_bytes();
261
void WAVEFILE::find_riff_datablock (void) throw(AUDIO_IO::SETUP_ERROR&)
263
if (find_block("data", 0) != true) {
264
throw(ECA_ERROR("AUDIOIO-WAVE", "no RIFF data block found", ECA_ERROR::retry));
266
data_start_position_rep = fio_repp->get_file_position();
269
void WAVEFILE::read_riff_header (void) throw(AUDIO_IO::SETUP_ERROR&)
271
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "read_riff_header()");
273
fio_repp->read_to_buffer(&riff_header_rep, sizeof(riff_header_rep));
275
// fread(&riff_header_rep,1,sizeof(riff_header_rep),fobject);
276
if ((memcmp("RIFF",riff_header_rep.id,4) == 0 &&
277
memcmp("WAVE",riff_header_rep.wname,4) == 0) != true) {
278
throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-WAVE: invalid RIFF-header (read)"));
282
void WAVEFILE::write_riff_header (void) throw(AUDIO_IO::SETUP_ERROR&)
284
ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_header()");
286
off_t savetemp = fio_repp->get_file_position();
288
memcpy(riff_header_rep.id,"RIFF",4);
289
memcpy(riff_header_rep.wname,"WAVE",4);
291
/* hack for 64bit wav files */
292
#if _FILE_OFFSET_BITS == 64
293
if (fio_repp->get_file_length() > static_cast<off_t>(UINT32_MAX))
294
riff_header_rep.size = little_endian_uint32(UINT32_MAX);
297
if (fio_repp->get_file_length() > static_cast<off_t>(sizeof(riff_header_rep)))
298
riff_header_rep.size = little_endian_uint32(fio_repp->get_file_length() - sizeof(riff_header_rep));
300
riff_header_rep.size = little_endian_uint32(0);
302
fio_repp->set_file_position(0);
303
// fseek(fobject,0,SEEK_SET);
305
fio_repp->write_from_buffer(&riff_header_rep, sizeof(riff_header_rep));
306
// fwrite(&riff_header_rep,1,sizeof(riff_header_rep),fobject);
307
if (memcmp("RIFF",riff_header_rep.id,4) != 0 ||
308
memcmp("WAVE",riff_header_rep.wname,4) != 0)
309
throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-WAVE: invalid RIFF-header (write)"));
311
ECA_LOG_MSG(ECA_LOGGER::user_objects, "Wave data size " + kvu_numtostr(little_endian_uint32(riff_header_rep.size)));
313
fio_repp->set_file_position(savetemp);
316
void WAVEFILE::read_riff_fmt(void) throw(AUDIO_IO::SETUP_ERROR&)
318
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "read_riff_fmt()");
320
off_t savetemp = fio_repp->get_file_position();
322
if (find_block("fmt ", 0) != true)
323
throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-WAVE: no riff fmt-block found"));
325
fio_repp->read_to_buffer(&riff_format_rep, sizeof(riff_format_rep));
326
// fread(&riff_format_rep,1,sizeof(riff_format_rep),fobject);
328
#ifdef DEBUG_WAVE_HEADER
329
std::cout << "RF: format = " << little_endian_uint16(riff_format_rep.format) << std::endl;
330
std::cout << "RF: channels = " << little_endian_uint16(riff_format_rep.channels) << std::endl;
331
std::cout << "RF: srate = " << little_endian_uint32(riff_format_rep.srate) << std::endl;
332
std::cout << "RF: byte_second = " << little_endian_uint32(riff_format_rep.byte_second) << std::endl;
333
std::cout << "RF: align = " << little_endian_uint16(riff_format_rep.align) << std::endl;
334
std::cout << "RF: bits = " << little_endian_uint16(riff_format_rep.bits) << std::endl;
337
if (little_endian_uint16(riff_format_rep.format) != 1 &&
338
little_endian_uint16(riff_format_rep.format) != 3) {
339
throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: Only WAVE_FORMAT_PCM and WAVE_FORMAT_IEEE_FLOAT are supported."));
342
set_samples_per_second(little_endian_uint32(riff_format_rep.srate));
343
set_channels(little_endian_uint16(riff_format_rep.channels));
345
if (little_endian_uint16(riff_format_rep.bits) == 32) {
346
if (little_endian_uint16(riff_format_rep.format) == 3)
347
set_sample_format(ECA_AUDIO_FORMAT::sfmt_f32_le);
349
set_sample_format(ECA_AUDIO_FORMAT::sfmt_s32_le);
351
else if (little_endian_uint16(riff_format_rep.bits) == 24) {
352
if (riff_format_rep.align == little_endian_uint16(channels() * 3)) {
353
/* packet s24 format */
354
set_sample_format(ECA_AUDIO_FORMAT::sfmt_s24_le);
356
else if (riff_format_rep.align == little_endian_uint16(channels() * 4)) {
357
/* unpacked s24 format */
358
set_sample_format(ECA_AUDIO_FORMAT::sfmt_s32_le);
361
throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: Invalid 24bit sample format combination."));
364
else if (little_endian_uint16(riff_format_rep.bits) == 16)
365
set_sample_format(ECA_AUDIO_FORMAT::sfmt_s16_le);
366
else if (little_endian_uint16(riff_format_rep.bits) == 8)
367
set_sample_format(ECA_AUDIO_FORMAT::sfmt_u8);
369
throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: Sample format not supported."));
372
DBC_CHECK(little_endian_uint16(riff_format_rep.channels) == channels());
373
DBC_CHECK(little_endian_uint16(riff_format_rep.bits) == bits());
374
DBC_CHECK(little_endian_uint32(riff_format_rep.srate) == static_cast<uint32_t>(samples_per_second()));
375
DBC_CHECK(little_endian_uint32(riff_format_rep.byte_second) == static_cast<uint32_t>(bytes_per_second()));
376
DBC_CHECK(little_endian_uint16(riff_format_rep.align) == frame_size());
378
fio_repp->set_file_position(savetemp);
381
void WAVEFILE::write_riff_fmt(void)
383
ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_fmt()");
387
fio_repp->set_file_position_end();
389
riff_format_rep.channels = little_endian_uint16(channels());
390
riff_format_rep.bits = little_endian_uint16(bits());
391
riff_format_rep.srate = little_endian_uint32(samples_per_second());
392
riff_format_rep.byte_second = little_endian_uint32(bytes_per_second());
393
riff_format_rep.align = little_endian_uint16(frame_size());
394
if (sample_coding() == ECA_AUDIO_FORMAT::sc_float) {
395
// WAVE_FORMAT_IEEE_FLOAT 0x0003 (Microsoft IEEE754 range [-1, +1))
396
riff_format_rep.format = little_endian_uint16(3);
399
// WAVE_FORMAT_PCM (0x0001) Microsoft Pulse Code Modulation (PCM) format
400
riff_format_rep.format = little_endian_uint16(1);
403
memcpy(fblock.sig, "fmt ", 4);
404
fblock.bsize = little_endian_uint32(16);
406
fio_repp->write_from_buffer(&fblock, sizeof(fblock));
407
fio_repp->write_from_buffer(&riff_format_rep, sizeof(riff_format_rep));
408
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "Wrote RIFF format header.");
411
void WAVEFILE::write_riff_datablock(void)
413
ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_datablock()");
417
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_datablock()");
419
fio_repp->set_file_position_end();
421
memcpy(fblock.sig,"data",4);
422
fblock.bsize = little_endian_uint32(0);
423
fio_repp->write_from_buffer(&fblock, sizeof(fblock));
424
data_start_position_rep = fio_repp->get_file_position();
427
void WAVEFILE::update_riff_datablock(void)
429
ECA_LOG_MSG(ECA_LOGGER::user_objects, "update_riff_datablock()");
433
memcpy(fblock.sig,"data",4);
435
find_block("data", 0);
436
off_t savetemp = fio_repp->get_file_position();
438
fio_repp->set_file_position_end();
440
/* hack for wav files with length over 2^32-1 bytes */
441
#if _FILE_OFFSET_BITS == 64
442
if (fio_repp->get_file_position() - savetemp > static_cast<off_t>(UINT32_MAX))
443
fblock.bsize = little_endian_uint32(UINT32_MAX);
446
fblock.bsize = little_endian_uint32(fio_repp->get_file_position() - savetemp);
448
ECA_LOG_MSG(ECA_LOGGER::user_objects,
449
"updating data block header length to " +
450
kvu_numtostr(little_endian_uint32(fblock.bsize)));
452
savetemp = savetemp - sizeof(fblock);
454
fio_repp->set_file_position(savetemp);
455
fio_repp->write_from_buffer(&fblock, sizeof(fblock));
459
bool WAVEFILE::next_riff_block(RB *t, off_t *offtmp)
461
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "next_riff_block()");
463
fio_repp->read_to_buffer(t, sizeof(RB));
464
if (fio_repp->file_bytes_processed() != sizeof(RB)) {
465
ECA_LOG_MSG(ECA_LOGGER::user_objects, "invalid RIFF block!");
469
if (!fio_repp->is_file_ready()) return false;
470
*offtmp = little_endian_uint32(t->bsize) + fio_repp->get_file_position();
474
bool WAVEFILE::find_block(const char* fblock, uint32_t* blksize)
479
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "find_block(): " + string(fblock,4));
481
fio_repp->set_file_position(sizeof(riff_header_rep));
482
while(next_riff_block(&block,&offset)) {
483
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "found RIFF-block ");
484
if (memcmp(block.sig,fblock,4) == 0) {
486
*blksize = little_endian_uint32(block.bsize);
489
fio_repp->set_file_position(offset);
495
bool WAVEFILE::finished(void) const
497
if (io_mode() == io_read &&
498
(length_set() == true &&
499
position_in_samples() >= length_in_samples())) {
503
if (fio_repp->is_file_error() ||
504
!fio_repp->is_file_ready())
510
long int WAVEFILE::read_samples(void* target_buffer, long int samples)
513
DBC_REQUIRE(samples >= 0);
514
DBC_REQUIRE(target_buffer != 0);
517
if (length_set() == true &&
518
position_in_samples() + samples >= length_in_samples())
519
samples = length_in_samples() - position_in_samples();
521
fio_repp->read_to_buffer(target_buffer, frame_size() * samples);
522
return fio_repp->file_bytes_processed() / frame_size();
525
void WAVEFILE::write_samples(void* target_buffer, long int samples)
528
DBC_REQUIRE(samples >= 0);
529
DBC_REQUIRE(target_buffer != 0);
532
/* note: When writing in write-update mode (i.e. modifying an
533
* existing file), we do not honor the previous length value
534
* in "data" header chunk. This may lead to overriding some
535
* non-data chunk at the end of the file.
538
fio_repp->write_from_buffer(target_buffer, frame_size() * samples);
541
SAMPLE_SPECS::sample_pos_t WAVEFILE::seek_position(SAMPLE_SPECS::sample_pos_t pos)
543
if (is_open() == true) {
544
fio_repp->set_file_position(data_start_position_rep + pos * frame_size());
550
void WAVEFILE::set_length_in_bytes(void)
552
off_t savetemp = fio_repp->get_file_position();
553
uint32_t blksize = 0;
555
find_block("data", &blksize);
556
off_t datastart = fio_repp->get_file_position();
558
fio_repp->set_file_position_end();
559
off_t datalen = fio_repp->get_file_position() - datastart;
561
/* note: If the audio stream length defined in "data" header
562
* block is zero (not updated), or it's set to maximum
563
* value, set the length according to actual file length.
565
* This is not strictly according to the RIFF WAVE spec,
566
* but allows to handle RIFF WAVE files with a broken
567
* header, as well as files with size exceeding the 2GiB
570
blksize != UINT32_MAX) {
571
set_length_in_samples(blksize / frame_size());
574
set_length_in_samples(datalen / frame_size());
576
ECA_LOG_MSG(ECA_LOGGER::user_objects,
577
"data block length in header " +
578
kvu_numtostr(blksize) +
579
", file length after data block " +
580
kvu_numtostr(datalen) +
582
kvu_numtostr(length_in_samples()) +
585
fio_repp->set_file_position(savetemp);
588
void WAVEFILE::set_parameter(int param,
597
mmaptoggle_rep = value;
602
string WAVEFILE::get_parameter(int param) const
609
return mmaptoggle_rep;