}
earliest->done = earliest->decoder->pass ();
+ if (earliest->done && earliest->content->audio) {
+ /* Flush the Player audio system for this piece */
+ BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) {
+ audio_flush (earliest, i);
+ }
+ }
/* Emit any audio that is ready */
}
void
-Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
+Player::audio_flush (shared_ptr<Piece> piece, AudioStreamPtr stream)
{
- shared_ptr<Piece> piece = wp.lock ();
- if (!piece) {
- return;
- }
-
shared_ptr<AudioContent> content = piece->content->audio;
DCPOMATIC_ASSERT (content);
+ shared_ptr<Resampler> r = resampler (content, stream);
+ pair<shared_ptr<const AudioBuffers>, Frame> ro = r->flush ();
+ ContentAudio content_audio;
+ content_audio.audio = ro.first;
+ content_audio.frame = ro.second;
+
+ /* Compute time in the DCP */
+ DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+
+ audio_transform (content, stream, content_audio, time);
+}
+
+/** Do our common processing on some audio */
+void
+Player::audio_transform (shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time)
+{
/* Gain */
+
if (content->gain() != 0) {
shared_ptr<AudioBuffers> gain (new AudioBuffers (content_audio.audio));
gain->apply_gain (content->gain ());
content_audio.audio = gain;
}
- /* Resample */
- if (stream->frame_rate() != content->resampled_frame_rate()) {
- shared_ptr<Resampler> r = resampler (content, stream, true);
- pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
- content_audio.audio = ro.first;
- content_audio.frame = ro.second;
- }
-
- /* XXX: end-trimming used to be checked here */
-
- /* Compute time in the DCP */
- DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+ /* Remap */
- /* Remove anything that comes before the start of the content */
- if (time < piece->content->position()) {
- DCPTime const discard_time = piece->content->position() - time;
- Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
- Frame remaining_frames = content_audio.audio->frames() - discard_frames;
- if (remaining_frames <= 0) {
- /* This audio is entirely discarded */
- return;
- }
- shared_ptr<AudioBuffers> cut (new AudioBuffers (content_audio.audio->channels(), remaining_frames));
- cut->copy_from (content_audio.audio.get(), remaining_frames, discard_frames, 0);
- content_audio.audio = cut;
- time += discard_time;
- }
-
- /* Remap channels */
shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), content_audio.audio->frames()));
dcp_mapped->make_silent ();
content_audio.audio = dcp_mapped;
+ /* Process */
+
if (_audio_processor) {
content_audio.audio = _audio_processor->run (content_audio.audio, _film->audio_channels ());
}
- _audio_merger.push (content_audio.audio, time);
+ /* Push */
+ _audio_merger.push (content_audio.audio, time);
DCPOMATIC_ASSERT (_stream_states.find (stream) != _stream_states.end ());
_stream_states[stream].last_push_end = time + DCPTime::from_frames (content_audio.audio->frames(), _film->audio_frame_rate());
}
+void
+Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
+{
+ shared_ptr<Piece> piece = wp.lock ();
+ if (!piece) {
+ return;
+ }
+
+ shared_ptr<AudioContent> content = piece->content->audio;
+ DCPOMATIC_ASSERT (content);
+
+ /* Resample */
+ if (stream->frame_rate() != content->resampled_frame_rate()) {
+ shared_ptr<Resampler> r = resampler (content, stream);
+ pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
+ content_audio.audio = ro.first;
+ content_audio.frame = ro.second;
+ }
+
+ /* XXX: end-trimming used to be checked here */
+
+ /* Compute time in the DCP */
+ DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+
+ /* Remove anything that comes before the start of the content */
+ if (time < piece->content->position()) {
+ DCPTime const discard_time = piece->content->position() - time;
+ Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
+ Frame remaining_frames = content_audio.audio->frames() - discard_frames;
+ if (remaining_frames <= 0) {
+ /* This audio is entirely discarded */
+ return;
+ }
+ shared_ptr<AudioBuffers> cut (new AudioBuffers (content_audio.audio->channels(), remaining_frames));
+ cut->copy_from (content_audio.audio.get(), remaining_frames, discard_frames, 0);
+ content_audio.audio = cut;
+ time += discard_time;
+ }
+
+ audio_transform (content, stream, content_audio, time);
+}
+
void
Player::image_subtitle (weak_ptr<Piece> wp, ContentImageSubtitle subtitle)
{
void
Player::seek (DCPTime time, bool accurate)
{
+ if (_audio_processor) {
+ _audio_processor->flush ();
+ }
+
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
if (i->content->position() <= time && time < i->content->end()) {
i->decoder->seek (dcp_to_content_time (i, time), accurate);
}
shared_ptr<Resampler>
-Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create)
+Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream)
{
ResamplerMap::const_iterator i = _resamplers.find (make_pair (content, stream));
if (i != _resamplers.end ()) {
return i->second;
}
- if (!create) {
- return shared_ptr<Resampler> ();
- }
-
LOG_GENERAL (
"Creating new resampler from %1 to %2 with %3 channels",
stream->frame_rate(),
using boost::shared_ptr;
+static SNDFILE* L;
+static SNDFILE* R;
+static SNDFILE* C;
+static SNDFILE* Lfe;
+static SNDFILE* Ls;
+static SNDFILE* Rs;
+
+static void
+write (shared_ptr<AudioBuffers> b, DCPTime)
+{
+ sf_write_float (L, b->data(0), b->frames());
+ sf_write_float (R, b->data(1), b->frames());
+ sf_write_float (C, b->data(2), b->frames());
+ sf_write_float (Lfe, b->data(3), b->frames());
+ sf_write_float (Ls, b->data(4), b->frames());
+ sf_write_float (Rs, b->data(5), b->frames());
+
+}
+
BOOST_AUTO_TEST_CASE (upmixer_a_test)
{
shared_ptr<Film> film = new_test_film ("upmixer_a_test");
info.samplerate = 48000;
info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
- SNDFILE* L = sf_open ("build/test/upmixer_a_test/L.wav", SFM_WRITE, &info);
- SNDFILE* R = sf_open ("build/test/upmixer_a_test/R.wav", SFM_WRITE, &info);
- SNDFILE* C = sf_open ("build/test/upmixer_a_test/C.wav", SFM_WRITE, &info);
- SNDFILE* Lfe = sf_open ("build/test/upmixer_a_test/Lfe.wav", SFM_WRITE, &info);
- SNDFILE* Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info);
- SNDFILE* Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info);
+ L = sf_open ("build/test/upmixer_a_test/L.wav", SFM_WRITE, &info);
+ R = sf_open ("build/test/upmixer_a_test/R.wav", SFM_WRITE, &info);
+ C = sf_open ("build/test/upmixer_a_test/C.wav", SFM_WRITE, &info);
+ Lfe = sf_open ("build/test/upmixer_a_test/Lfe.wav", SFM_WRITE, &info);
+ Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info);
+ Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info);
shared_ptr<Player> player (new Player (film, film->playlist ()));
- for (DCPTime t; t < film->length(); t += DCPTime::from_seconds (1)) {
- shared_ptr<AudioBuffers> b = player->get_audio (t, DCPTime::from_seconds (1), true);
- sf_write_float (L, b->data(0), b->frames());
- sf_write_float (R, b->data(1), b->frames());
- sf_write_float (C, b->data(2), b->frames());
- sf_write_float (Lfe, b->data(3), b->frames());
- sf_write_float (Ls, b->data(4), b->frames());
- sf_write_float (Rs, b->data(5), b->frames());
- }
+ player->Audio.connect (bind (&write, _1, _2));
+ while (!player->pass()) {}
sf_close (L);
sf_close (R);