1
// ------------------------------------------------------------------------
2
// audioio-seqbase.cpp: Base class for audio sequencer objects
3
// Copyright (C) 1999,2002,2005,2008 Kai Vehmanen
6
// eca-style-version: 3 (see Ecasound Programmer's Guide)
8
// This program is free software; you can redistribute it and/or modify
9
// it under the terms of the GNU General Public License as published by
10
// the Free Software Foundation; either version 2 of the License, or
11
// (at your option) any later version.
13
// This program is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
// GNU General Public License for more details.
18
// You should have received a copy of the GNU General Public License
19
// along with this program; if not, write to the Free Software
20
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
// ------------------------------------------------------------------------
30
#include <kvu_message_item.h>
31
#include <kvu_numtostr.h>
34
#include "eca-object-factory.h"
35
#include "samplebuffer.h"
36
#include "audioio-seqbase.h"
38
#include "eca-error.h"
39
#include "eca-logger.h"
43
using SAMPLE_SPECS::sample_pos_t;
46
* FIXME notes (last update 2008-03-04)
48
* - Add check for supports_sample_accurate_seek(). This could
49
* be used to warn users if EWF source file cannot provide
50
* accurate enough seeking (which will lead to unexpected
52
* - Remove write-support altogether (changes supported io_modes(),
53
* modify write_buffer(), and remove child_write_started.
54
* - Should extend the object length when looping is enabled.
58
* Returns the child position in samples for the given
61
sample_pos_t AUDIO_SEQUENCER_BASE::priv_public_to_child_pos(sample_pos_t pubpos) const
63
if (pubpos <= child_offset_rep.samples())
64
return child_start_pos_rep.samples();
66
if (child_looping_rep == true) {
67
DBC_CHECK(child()->finite_length_stream() == true);
68
sample_pos_t one_loop =
69
child_length_rep.samples() -
70
child_start_pos_rep.samples();
72
pubpos - child_offset_rep.samples();
76
return res + child_start_pos_rep.samples();
80
return pubpos - child_offset_rep.samples() + child_start_pos_rep.samples();
84
AUDIO_SEQUENCER_BASE::AUDIO_SEQUENCER_BASE (void)
85
: child_looping_rep(false),
86
child_length_set_by_client_rep(false),
88
child_write_started(false),
93
AUDIO_SEQUENCER_BASE::~AUDIO_SEQUENCER_BASE(void)
97
AUDIO_SEQUENCER_BASE* AUDIO_SEQUENCER_BASE::clone(void) const
99
AUDIO_SEQUENCER_BASE* target = new AUDIO_SEQUENCER_BASE();
100
for(int n = 0; n < number_of_params(); n++) {
101
target->set_parameter(n + 1, get_parameter(n + 1));
106
void AUDIO_SEQUENCER_BASE::open(void) throw(AUDIO_IO::SETUP_ERROR &)
108
if (init_rep != true) {
109
AUDIO_IO* tmp = ECA_OBJECT_FACTORY::create_audio_object(child_name_rep);
111
throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-SEQBASE: Couldn't open child object."));
113
ECA_LOG_MSG(ECA_LOGGER::user_objects, "Opening audio sequencer file:" + tmp->label() + ".");
122
if (child()->finite_length_stream() != true &&
125
throw(SETUP_ERROR(SETUP_ERROR::unexpected, "AUDIOIO-SEQBASE: Unable to loop an object with infinite length."));
128
/* step: set srate for audio time variable */
129
child_offset_rep.set_samples_per_second_keeptime(child()->samples_per_second());
130
child_start_pos_rep.set_samples_per_second_keeptime(child()->samples_per_second());
131
child_length_rep.set_samples_per_second_keeptime(child()->samples_per_second());
135
/* step: unless overridden by the client, store the length
137
ECA_AUDIO_TIME len_tmp (child()->length_in_samples(),
138
child()->samples_per_second());
139
if (child_length_set_by_client_rep != true)
140
set_child_length_private(len_tmp);
141
else if (len_tmp.valid() == true &&
142
child_length_rep.valid() == true) {
143
if (len_tmp.seconds() <
144
child_length_rep.seconds())
145
ECA_LOG_MSG(ECA_LOGGER::info,
146
"WARNING: object '" + child()->label() +
147
"' is too short, reducing segment length to '"
148
+ kvu_numtostr(len_tmp.seconds()) + "'sec.");
151
/* step: set public length of the EWF object;
152
* child length is infinite, we will extend our object
153
* length in read_buffer(), see also
154
* AUDIO_SEQUENCER_BASE::finite_length_stream() */
155
if (child_looping_rep != true)
156
set_length_in_samples(child_offset_rep.samples() + child_length_rep.samples());
158
//dump_child_debug();
160
tmp_buffer.number_of_channels(child()->channels());
161
tmp_buffer.length_in_samples(child()->buffersize());
163
AUDIO_IO_PROXY::open();
166
void AUDIO_SEQUENCER_BASE::close(void)
168
if (child()->is_open() == true)
171
AUDIO_IO_PROXY::close();
175
void AUDIO_SEQUENCER_BASE::read_buffer(SAMPLE_BUFFER* sbuf)
178
* implementation notes:
180
* position: the current global position (note, this
181
* can exceed child_offset+child_length when
183
* child_offset: global position when child is activated
184
* child_start_position: position inside the child-object where
185
* input is started (data between child
186
* beginning and child_start_pos is not used)
187
* child_length: amount of child data between start and end
188
* positions (end can in middle of stream or
189
* at end-of-file position)
190
* child_looping: when child end is reached, whether to jump
191
* back to start position?
193
* note! all cases (if-else blocks) end to setting a new
194
* position_in_samples value
197
//dump_child_debug();
199
if (position_in_samples() + buffersize() <= child_offset_rep.samples()) {
201
// case 1: child not active yet
204
/* ensure that channel count matches that of child */
205
sbuf->number_of_channels(child()->channels());
206
change_position_in_samples(buffersize());
208
else if (position_in_samples() < child_offset_rep.samples()) {
210
// case 2: next read will bring in the first child samples
213
DBC_CHECK(position_in_samples() + buffersize() > child_offset_rep.samples());
215
/* make sure child position is correct at start */
216
sample_pos_t chipos =
217
priv_public_to_child_pos(position_in_samples());
218
if (chipos != child()->position_in_samples())
219
child()->seek_position_in_samples(chipos);
221
sample_pos_t segment =
222
position_in_samples()
224
- child_offset_rep.samples();
226
if (segment > buffersize())
227
segment = buffersize();
229
ECA_LOG_MSG(ECA_LOGGER::user_objects,
230
"child-object '" + child()->label() + "' activated.");
232
/* step: read segment of audio and copy it to the correct
234
long int save_bsize = child()->buffersize();
235
DBC_CHECK(save_bsize == buffersize());
236
child()->set_buffersize(segment);
237
child()->read_buffer(&tmp_buffer);
238
sbuf->copy_range(tmp_buffer,
240
tmp_buffer.length_in_samples(),
241
buffersize() - segment);
242
/* ensure that channel count matches that of child */
243
sbuf->number_of_channels(child()->channels());
244
child()->set_buffersize(save_bsize);
245
change_position_in_samples(buffersize());
249
// case 3: child is active
252
sample_pos_t chipos1 =
253
priv_public_to_child_pos(position_in_samples());
254
sample_pos_t chipos2 =
255
priv_public_to_child_pos(position_in_samples() + buffersize());
258
(child_length_rep.samples() + child_start_pos_rep.samples()) &&
259
child_looping_rep != true &&
260
child()->finite_length_stream() == true) {
262
// case 3a: not looping, reaching child file end during the next read
265
child()->read_buffer(sbuf);
267
sample_pos_t over_child_eof =
268
chipos2 - (child_length_rep.samples() + child_start_pos_rep.samples());
270
DBC_CHECK(over_child_eof >= 0);
271
DBC_CHECK((child()->finished() == true &&
272
buffersize() > sbuf->length_in_samples()) ||
273
child()->finished() != true);
275
/* resize the sbuf if needed: either EOF was encountered
276
* and sbuf is shorter than buffersize() or otherwise we
277
* need to drop some of the samples read so at to not
278
* go beyond set length */
279
sample_pos_t data_left = buffersize() - over_child_eof;
280
sbuf->length_in_samples(data_left);
281
change_position_in_samples(sbuf->length_in_samples());
283
else if (chipos2 < chipos1 &&
284
child_looping_rep == true) {
286
// case 3b: looping, we will run out of data during read
289
child()->read_buffer(sbuf);
291
sample_pos_t over_child_eof = chipos2 - child_start_pos_rep.samples();
293
/* step: copy segment 1 from loop end, and segment 2 from
294
* loop start point */
295
sample_pos_t chistartpos =
296
priv_public_to_child_pos(position_in_samples() +
297
buffersize() - over_child_eof);
299
DBC_CHECK(chistartpos == child_start_pos_rep.samples());
300
child()->seek_position_in_samples(chistartpos);
302
if (over_child_eof > 0) {
303
long int save_bsize = child()->buffersize();
304
DBC_CHECK(save_bsize == buffersize());
305
child()->set_buffersize(over_child_eof);
306
tmp_buffer.number_of_channels(channels());
307
child()->read_buffer(&tmp_buffer);
308
DBC_CHECK(tmp_buffer.length_in_samples() == over_child_eof);
309
child()->set_buffersize(save_bsize);
310
DBC_CHECK((buffersize() - over_child_eof) < buffersize());
311
sbuf->length_in_samples(buffersize());
312
sbuf->copy_range(tmp_buffer,
314
tmp_buffer.length_in_samples(),
315
buffersize() - over_child_eof);
317
change_position_in_samples(buffersize());
321
// case 3c: normal case, read samples from child
324
child()->set_buffersize(buffersize());
325
child()->read_buffer(sbuf);
326
/* note: if the 'length' parameter value is longer than
327
* actual child object length, less than buffersize()
328
* samples will be read */
330
change_position_in_samples(sbuf->length_in_samples());
334
/* note: as we are looping indefinitely, so our length must
335
* be continuously updated (see child_lengt() implementation) */
336
if (child_looping_rep == true ||
337
(child_length_set_by_client_rep != true &&
338
child()->finite_length_stream() != true))
342
void AUDIO_SEQUENCER_BASE::dump_child_debug(void)
344
cout << "global position (in samples): " << position_in_samples() << endl;
345
cout << "child-pos: " << child()->position_in_samples() << endl;
346
cout << "child-offset: " << child_offset_rep.samples() << endl;
347
cout << "child-startpos: " << child_start_pos_rep.samples() << endl;
348
cout << "child-length: " << child_length_rep.samples() << endl;
351
void AUDIO_SEQUENCER_BASE::write_buffer(SAMPLE_BUFFER* sbuf)
353
if (child_write_started != true) {
354
child_write_started = true;
355
child_offset_rep.set_samples(position_in_samples());
357
m << "found child_offset_rep " << child_offset_rep.seconds() << ".";
358
ECA_LOG_MSG(ECA_LOGGER::user_objects, m.to_string());
361
child()->write_buffer(sbuf);
362
change_position_in_samples(sbuf->length_in_samples());
366
SAMPLE_SPECS::sample_pos_t AUDIO_SEQUENCER_BASE::seek_position(SAMPLE_SPECS::sample_pos_t pos)
368
/* in write mode, seek can be only performed once
369
* the initial write has been performed to the child */
370
if (is_open() == true &&
371
(io_mode() == AUDIO_IO::io_read ||
372
(io_mode() != AUDIO_IO::io_read &&
373
child_write_started == true))) {
374
sample_pos_t chipos =
375
priv_public_to_child_pos(pos);
377
child()->seek_position_in_samples(chipos);
383
void AUDIO_SEQUENCER_BASE::set_child_object_string(const std::string& v)
388
void AUDIO_SEQUENCER_BASE::set_child_offset(const ECA_AUDIO_TIME& v)
390
child_offset_rep = v;
393
void AUDIO_SEQUENCER_BASE::set_child_start_position(const ECA_AUDIO_TIME& v)
395
child_start_pos_rep = v;
398
void AUDIO_SEQUENCER_BASE::set_child_length_private(const ECA_AUDIO_TIME& v)
400
child_length_rep = v;
403
void AUDIO_SEQUENCER_BASE::set_child_length(const ECA_AUDIO_TIME& v)
405
set_child_length_private(v);
406
child_length_set_by_client_rep = true;
409
ECA_AUDIO_TIME AUDIO_SEQUENCER_BASE::child_length(void) const
411
/* case: infinite child length */
412
if (child_length_set_by_client_rep != true &&
413
child()->finite_length_stream() != true) {
415
tmp.mark_as_invalid();
419
return child_length_rep;
422
bool AUDIO_SEQUENCER_BASE::finite_length_stream(void) const
424
if (child_looping_rep == true)
427
return child()->finite_length_stream();
430
bool AUDIO_SEQUENCER_BASE::finished(void) const
433
* File is finished if...
434
* 1) the child object is out of data (implies that looping
436
* 2) file is open in read mode, looping is disabled, child is
437
* a finite length stream and its position has gone beyond
438
* the requested child_length
440
if (child()->finished()) {
441
ECA_LOG_MSG(ECA_LOGGER::user_objects,
442
"Child object " + child()->label() + " finished.");
446
if (io_mode() != AUDIO_IO::io_read) {
450
if (child_looping_rep != true &&
451
child()->finite_length_stream() == true &&
452
priv_public_to_child_pos(position_in_samples())
453
>= child_length_rep.samples() + child_start_pos_rep.samples()) {
454
ECA_LOG_MSG(ECA_LOGGER::user_objects,
455
"Finite length child object " + child()->label() +
456
" finished. All samples from the requested range have been read.");