~ubuntu-branches/ubuntu/wily/ecasound/wily-proposed

« back to all changes in this revision

Viewing changes to libecasound/audioio-wave.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-12 17:58:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110512175803-zy3lodjecabt9r3v
Tags: upstream-2.8.0
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ------------------------------------------------------------------------
 
2
// audioio-wave.cpp: RIFF WAVE audio file input/output.
 
3
// Copyright (C) 1999-2003,2005,2008,2009 Kai Vehmanen
 
4
//
 
5
// Attributes:
 
6
//     eca-style-version: 3
 
7
//
 
8
// References:
 
9
//     - http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
 
10
//
 
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.
 
15
// 
 
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.
 
20
// 
 
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
// ------------------------------------------------------------------------
 
25
 
 
26
#ifdef HAVE_CONFIG_H
 
27
#include <config.h>
 
28
#endif
 
29
 
 
30
#include <cstdio>
 
31
#include <cstring>
 
32
#include <cmath>
 
33
#include <string>
 
34
#ifdef HAVE_SYS_TYPES_H
 
35
#include <sys/types.h> /* off_t */
 
36
#endif
 
37
 
 
38
#include <kvu_message_item.h>
 
39
#include <kvu_numtostr.h>
 
40
#include <kvu_dbc.h>
 
41
 
 
42
#include "sample-specs.h" /* for system endianess */
 
43
#include "samplebuffer.h"
 
44
#include "audioio-wave.h"
 
45
 
 
46
#include "eca-fileio-mmap.h"
 
47
#include "eca-fileio-stream.h"
 
48
 
 
49
#include "eca-logger.h"
 
50
 
 
51
/**
 
52
 * Private macro definitions
 
53
 */
 
54
 
 
55
#ifndef UINT32_MAX
 
56
#define UINT32_MAX 4294967295U
 
57
#endif
 
58
 
 
59
#ifdef WORDS_BIGENDIAN
 
60
static const bool is_system_littleendian = false;
 
61
#else
 
62
static const bool is_system_littleendian = true;
 
63
#endif
 
64
 
 
65
/**
 
66
 * Private function declarations 
 
67
 */
 
68
 
 
69
static uint16_t little_endian_uint16(uint16_t arg);
 
70
static uint32_t little_endian_uint32(uint32_t arg);
 
71
 
 
72
/**
 
73
 * Private function definitions
 
74
 */
 
75
 
 
76
static uint16_t little_endian_uint16(uint16_t arg)
 
77
{
 
78
  if (is_system_littleendian != true) {
 
79
    return ((arg >> 8) & 0x00ff) | ((arg << 8) & 0xff00);
 
80
  }
 
81
  return arg;
 
82
}
 
83
 
 
84
static uint32_t little_endian_uint32(uint32_t arg)
 
85
{
 
86
  if (is_system_littleendian != true) {
 
87
    return ((arg >> 24) & 0x000000ff) |
 
88
           ((arg >> 8)  & 0x0000ff00) |
 
89
           ((arg << 8)  & 0x00ff0000) |
 
90
           ((arg << 24) & 0xff000000);
 
91
  }
 
92
  return arg;
 
93
}
 
94
 
 
95
/**
 
96
 * Public definitions
 
97
 */
 
98
 
 
99
/**
 
100
 * Print extra debug information about RIFF header 
 
101
 * contents to stdout when opening files.
 
102
 */
 
103
// #define DEBUG_WAVE_HEADER
 
104
 
 
105
WAVEFILE::WAVEFILE (const std::string& name)
 
106
{
 
107
  set_label(name);
 
108
  fio_repp = 0;
 
109
  mmaptoggle_rep = "0";
 
110
}
 
111
 
 
112
WAVEFILE::~WAVEFILE(void)
 
113
{
 
114
  if (is_open() == true) {
 
115
    close();
 
116
  }
 
117
}
 
118
 
 
119
WAVEFILE* WAVEFILE::clone(void) const
 
120
{
 
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));
 
124
  }
 
125
  return target;
 
126
}
 
127
 
 
128
void WAVEFILE::format_query(void) throw(AUDIO_IO::SETUP_ERROR&)
 
129
{
 
130
  // --------
 
131
  DBC_REQUIRE(is_open() != true);
 
132
  // --------
 
133
 
 
134
  if (io_mode() == io_write) return;
 
135
 
 
136
  fio_repp = new ECA_FILE_IO_STREAM();
 
137
  if (fio_repp == 0) {
 
138
    throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for reading."));
 
139
  }
 
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();
 
146
  }
 
147
  delete fio_repp;
 
148
  fio_repp = 0;
 
149
 
 
150
  // -------
 
151
  DBC_ENSURE(!is_open());
 
152
  DBC_ENSURE(fio_repp == 0);
 
153
  // -------
 
154
}
 
155
 
 
156
void WAVEFILE::open(void) throw (AUDIO_IO::SETUP_ERROR &)
 
157
{
 
158
  switch(io_mode()) {
 
159
  case io_read:
 
160
    {
 
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();
 
164
      }
 
165
      else  fio_repp = new ECA_FILE_IO_STREAM();
 
166
      if (fio_repp == 0) {
 
167
        throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for reading."));
 
168
      }
 
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."));
 
172
      }
 
173
      read_riff_header();
 
174
      read_riff_fmt();     // also sets format()
 
175
      set_length_in_bytes();
 
176
      find_riff_datablock();
 
177
      break;
 
178
    }
 
179
  case io_write:
 
180
    {
 
181
      fio_repp = new ECA_FILE_IO_STREAM();
 
182
      if (fio_repp == 0) {
 
183
        throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for writing."));
 
184
      }
 
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."));
 
188
      }
 
189
      write_riff_header();
 
190
      write_riff_fmt();
 
191
      write_riff_datablock();
 
192
      break;
 
193
    }
 
194
 
 
195
  case io_readwrite:
 
196
    {
 
197
      fio_repp = new ECA_FILE_IO_STREAM();
 
198
      if (fio_repp == 0) {
 
199
        throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-WAVE: Critical error when opening file \"" + label() + "\" for read&write."));
 
200
      }
 
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();
 
206
      }
 
207
      else {
 
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."));
 
211
 
 
212
        write_riff_header();
 
213
        write_riff_fmt();
 
214
        write_riff_datablock();
 
215
      }
 
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."));
 
218
      }
 
219
    }
 
220
  }
 
221
 
 
222
 
 
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."));
 
226
 
 
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');
 
234
  }
 
235
 
 
236
  AUDIO_IO::open();
 
237
}
 
238
 
 
239
void WAVEFILE::close(void)
 
240
{
 
241
  ECA_LOG_MSG(ECA_LOGGER::user_objects,"Closing file " + label());
 
242
  if (is_open() == true && fio_repp != 0) {
 
243
    update();
 
244
    fio_repp->close_file();
 
245
    delete fio_repp;
 
246
    fio_repp = 0;
 
247
  }
 
248
 
 
249
  AUDIO_IO::close();
 
250
}
 
251
 
 
252
void WAVEFILE::update (void)
 
253
{
 
254
  if (io_mode() != io_read) {
 
255
    update_riff_datablock();
 
256
    write_riff_header();
 
257
    set_length_in_bytes();
 
258
  }
 
259
}
 
260
 
 
261
void WAVEFILE::find_riff_datablock (void) throw(AUDIO_IO::SETUP_ERROR&)
 
262
{
 
263
  if (find_block("data", 0) != true) {
 
264
    throw(ECA_ERROR("AUDIOIO-WAVE", "no RIFF data block found", ECA_ERROR::retry));
 
265
  }
 
266
  data_start_position_rep = fio_repp->get_file_position();
 
267
}
 
268
 
 
269
void WAVEFILE::read_riff_header (void) throw(AUDIO_IO::SETUP_ERROR&) 
 
270
{
 
271
  //  ECA_LOG_MSG(ECA_LOGGER::user_objects, "read_riff_header()");
 
272
   
 
273
  fio_repp->read_to_buffer(&riff_header_rep, sizeof(riff_header_rep));
 
274
 
 
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)"));
 
279
  }
 
280
}
 
281
 
 
282
void WAVEFILE::write_riff_header (void) throw(AUDIO_IO::SETUP_ERROR&) 
 
283
{
 
284
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_header()");
 
285
 
 
286
  off_t savetemp = fio_repp->get_file_position();
 
287
    
 
288
  memcpy(riff_header_rep.id,"RIFF",4);
 
289
  memcpy(riff_header_rep.wname,"WAVE",4);
 
290
 
 
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);
 
295
  else 
 
296
#endif
 
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));
 
299
  else
 
300
    riff_header_rep.size = little_endian_uint32(0);
 
301
 
 
302
  fio_repp->set_file_position(0);
 
303
  //  fseek(fobject,0,SEEK_SET);
 
304
 
 
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)"));
 
310
 
 
311
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "Wave data size " + kvu_numtostr(little_endian_uint32(riff_header_rep.size)));
 
312
 
 
313
  fio_repp->set_file_position(savetemp);
 
314
}
 
315
 
 
316
void WAVEFILE::read_riff_fmt(void) throw(AUDIO_IO::SETUP_ERROR&)
 
317
{
 
318
  //  ECA_LOG_MSG(ECA_LOGGER::user_objects, "read_riff_fmt()");
 
319
 
 
320
  off_t savetemp = fio_repp->get_file_position();    
 
321
 
 
322
  if (find_block("fmt ", 0) != true)
 
323
    throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-WAVE: no riff fmt-block found"));
 
324
  else {
 
325
    fio_repp->read_to_buffer(&riff_format_rep, sizeof(riff_format_rep));
 
326
    //    fread(&riff_format_rep,1,sizeof(riff_format_rep),fobject);
 
327
 
 
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;
 
335
#endif
 
336
 
 
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."));
 
340
    }
 
341
    
 
342
    set_samples_per_second(little_endian_uint32(riff_format_rep.srate));
 
343
    set_channels(little_endian_uint16(riff_format_rep.channels));
 
344
 
 
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);
 
348
      else
 
349
        set_sample_format(ECA_AUDIO_FORMAT::sfmt_s32_le);
 
350
    }
 
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);
 
355
      }
 
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);
 
359
      }
 
360
      else {
 
361
        throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: Invalid 24bit sample format combination."));
 
362
      }
 
363
    }
 
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);
 
368
    else 
 
369
      throw(SETUP_ERROR(SETUP_ERROR::sample_format, "AUDIOIO-WAVE: Sample format not supported."));
 
370
  }
 
371
 
 
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());
 
377
 
 
378
  fio_repp->set_file_position(savetemp);
 
379
}
 
380
 
 
381
void WAVEFILE::write_riff_fmt(void)
 
382
{
 
383
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_fmt()");
 
384
 
 
385
  RB fblock;
 
386
 
 
387
  fio_repp->set_file_position_end();
 
388
 
 
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);
 
397
  }
 
398
  else {
 
399
    // WAVE_FORMAT_PCM (0x0001) Microsoft Pulse Code Modulation (PCM) format
 
400
    riff_format_rep.format = little_endian_uint16(1);
 
401
  }
 
402
 
 
403
  memcpy(fblock.sig, "fmt ", 4);
 
404
  fblock.bsize = little_endian_uint32(16);
 
405
 
 
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.");
 
409
}
 
410
 
 
411
void WAVEFILE::write_riff_datablock(void)
 
412
{
 
413
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_datablock()");
 
414
 
 
415
  RB fblock;
 
416
 
 
417
  //  ECA_LOG_MSG(ECA_LOGGER::user_objects, "write_riff_datablock()");
 
418
    
 
419
  fio_repp->set_file_position_end();
 
420
 
 
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();
 
425
}
 
426
 
 
427
void WAVEFILE::update_riff_datablock(void)
 
428
{
 
429
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "update_riff_datablock()");
 
430
 
 
431
  RB fblock;
 
432
    
 
433
  memcpy(fblock.sig,"data",4);
 
434
 
 
435
  find_block("data", 0);
 
436
  off_t savetemp = fio_repp->get_file_position();
 
437
 
 
438
  fio_repp->set_file_position_end();
 
439
 
 
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);
 
444
  else
 
445
#endif
 
446
    fblock.bsize = little_endian_uint32(fio_repp->get_file_position() - savetemp);
 
447
 
 
448
  ECA_LOG_MSG(ECA_LOGGER::user_objects, 
 
449
              "updating data block header length to " + 
 
450
              kvu_numtostr(little_endian_uint32(fblock.bsize)));
 
451
 
 
452
  savetemp = savetemp - sizeof(fblock);
 
453
  if (savetemp > 0) {
 
454
    fio_repp->set_file_position(savetemp);
 
455
    fio_repp->write_from_buffer(&fblock, sizeof(fblock));
 
456
  }
 
457
}
 
458
 
 
459
bool WAVEFILE::next_riff_block(RB *t, off_t *offtmp)
 
460
{
 
461
  //  ECA_LOG_MSG(ECA_LOGGER::user_objects, "next_riff_block()");
 
462
 
 
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!");
 
466
    return false;
 
467
  }
 
468
    
 
469
  if (!fio_repp->is_file_ready()) return false;
 
470
  *offtmp = little_endian_uint32(t->bsize) + fio_repp->get_file_position();
 
471
  return true;
 
472
}
 
473
 
 
474
bool WAVEFILE::find_block(const char* fblock, uint32_t* blksize)
 
475
{
 
476
  off_t offset;
 
477
  RB block;
 
478
 
 
479
  //  ECA_LOG_MSG(ECA_LOGGER::user_objects, "find_block(): " + string(fblock,4));
 
480
    
 
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) {
 
485
      if (blksize != 0)
 
486
        *blksize = little_endian_uint32(block.bsize);
 
487
      return true;
 
488
    }
 
489
    fio_repp->set_file_position(offset);
 
490
  }
 
491
 
 
492
  return false;
 
493
}
 
494
 
 
495
bool WAVEFILE::finished(void) const
 
496
{
 
497
  if (io_mode() == io_read && 
 
498
      (length_set() == true &&
 
499
       position_in_samples() >= length_in_samples())) {
 
500
    return true;
 
501
  }
 
502
 
 
503
  if (fio_repp->is_file_error() ||
 
504
      !fio_repp->is_file_ready()) 
 
505
    return true;
 
506
 
 
507
  return false;
 
508
}
 
509
 
 
510
long int WAVEFILE::read_samples(void* target_buffer, long int samples)
 
511
{
 
512
  // --------
 
513
  DBC_REQUIRE(samples >= 0);
 
514
  DBC_REQUIRE(target_buffer != 0);
 
515
  // --------
 
516
 
 
517
  if (length_set() == true &&
 
518
      position_in_samples() + samples >= length_in_samples())
 
519
    samples = length_in_samples() - position_in_samples();
 
520
  
 
521
  fio_repp->read_to_buffer(target_buffer, frame_size() * samples);
 
522
  return fio_repp->file_bytes_processed() / frame_size();
 
523
}
 
524
 
 
525
void WAVEFILE::write_samples(void* target_buffer, long int samples)
 
526
{
 
527
  // --------
 
528
  DBC_REQUIRE(samples >= 0);
 
529
  DBC_REQUIRE(target_buffer != 0);
 
530
  // --------
 
531
 
 
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.
 
536
   */
 
537
 
 
538
  fio_repp->write_from_buffer(target_buffer, frame_size() * samples);
 
539
}
 
540
 
 
541
SAMPLE_SPECS::sample_pos_t WAVEFILE::seek_position(SAMPLE_SPECS::sample_pos_t pos)
 
542
{
 
543
  if (is_open() == true) {
 
544
    fio_repp->set_file_position(data_start_position_rep + pos * frame_size());
 
545
  }
 
546
 
 
547
  return pos;
 
548
}
 
549
 
 
550
void WAVEFILE::set_length_in_bytes(void)
 
551
{
 
552
  off_t savetemp = fio_repp->get_file_position();
 
553
  uint32_t blksize = 0;
 
554
 
 
555
  find_block("data", &blksize);
 
556
  off_t datastart = fio_repp->get_file_position();
 
557
 
 
558
  fio_repp->set_file_position_end();
 
559
  off_t datalen = fio_repp->get_file_position() - datastart;
 
560
 
 
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.
 
564
   *       
 
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
 
568
   *       limit. */
 
569
  if (blksize != 0 &&
 
570
      blksize != UINT32_MAX) {
 
571
    set_length_in_samples(blksize / frame_size());
 
572
  }
 
573
  else 
 
574
    set_length_in_samples(datalen / frame_size());
 
575
 
 
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) + 
 
581
              ", length set to " +
 
582
              kvu_numtostr(length_in_samples()) + 
 
583
              " samples");
 
584
 
 
585
  fio_repp->set_file_position(savetemp);
 
586
}
 
587
 
 
588
void WAVEFILE::set_parameter(int param, 
 
589
                             string value)
 
590
{
 
591
  switch (param) {
 
592
  case 1: 
 
593
    set_label(value);
 
594
    break;
 
595
 
 
596
  case 2: 
 
597
    mmaptoggle_rep = value;
 
598
    break;
 
599
  }
 
600
}
 
601
 
 
602
string WAVEFILE::get_parameter(int param) const
 
603
{
 
604
  switch (param) {
 
605
  case 1: 
 
606
    return label();
 
607
 
 
608
  case 2: 
 
609
    return mmaptoggle_rep;
 
610
  }
 
611
  return "";
 
612
}