1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
/***************************************************************************
MultiPlaybackSink.cpp - multi-track Kwave playback sink
-------------------
begin : Sun Nov 04 2007
copyright : (C) 2007 by Thomas Eschenbacher
email : Thomas.Eschenbacher@gmx.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "config.h"
#include <new>
#include <QMutexLocker>
#include <QtGlobal>
#include <QThread>
#include "libkwave/MultiPlaybackSink.h"
#include "libkwave/PlayBackDevice.h"
#include "libkwave/PlaybackSink.h"
//***************************************************************************
Kwave::MultiPlaybackSink::MultiPlaybackSink(unsigned int tracks,
Kwave::PlayBackDevice *device)
:Kwave::MultiTrackSink<Kwave::PlaybackSink, false>(0),
m_tracks(tracks), m_device(device), m_in_buffer(tracks),
m_in_buffer_filled(tracks),
m_out_buffer(tracks), m_lock()
{
m_in_buffer.fill(Kwave::SampleArray(0));
m_in_buffer_filled.fill(false);
for (unsigned int track = 0; track < m_tracks; track++) {
// allocate a sink
Kwave::PlaybackSink *sink =
new(std::nothrow) Kwave::PlaybackSink(track);
insert(track, sink);
connect(sink, SIGNAL(output(uint,Kwave::SampleArray)),
this, SLOT(input(uint,Kwave::SampleArray)),
Qt::DirectConnection);
}
}
//***************************************************************************
Kwave::MultiPlaybackSink::~MultiPlaybackSink()
{
// close all stream objects
clear();
// close the device
if (m_device) {
m_device->close();
delete m_device;
m_device = nullptr;
}
// discard the buffers
while (!m_in_buffer.isEmpty())
m_in_buffer.erase(m_in_buffer.end() - 1);
m_in_buffer.clear();
}
//***************************************************************************
void Kwave::MultiPlaybackSink::input(unsigned int track,
Kwave::SampleArray data)
{
QMutexLocker lock(&m_lock);
// shortcut for more responsiveness when pressing cancel
if (isCanceled()) {
m_in_buffer_filled.fill(false);
return;
}
Q_ASSERT(m_device);
Q_ASSERT(m_tracks);
if (!m_device || !m_tracks) return;
Q_ASSERT(!m_in_buffer_filled[track]);
m_in_buffer_filled[track] = true;
// copy the input data to the buffer
unsigned int samples = data.size();
m_in_buffer[track] = data;
// check if all buffers are filled
for (unsigned int t = 0; t < m_tracks; t++)
if (!m_in_buffer_filled[t]) return;
// all tracks have left their data, now we are ready
// to convert the buffers into a big combined one
Q_ASSERT(m_out_buffer.size() >= m_tracks);
for (unsigned int sample = 0; sample < samples; sample++) {
for (unsigned int t = 0; t < m_tracks; t++) {
const Kwave::SampleArray &in = m_in_buffer[t];
m_out_buffer[t] = in[sample];
}
// play the output buffer
unsigned int retry = 5;
while (retry-- && !isCanceled()) {
int res = m_device->write(m_out_buffer);
if (res != 0) {
QThread::yieldCurrentThread();
} else break;
}
if (retry == 0)
break; // give up
}
m_in_buffer_filled.fill(false);
}
//***************************************************************************
//***************************************************************************
#include "moc_MultiPlaybackSink.cpp"
|