M example.pro +7 -9
@@ 7,9 7,7 @@ CONFIG += release c++11 object_parallel_
TARGET = "Example"
-DEFINES += USE_SPEEX USE_KISSFFT HAVE_PORTAUDIO
-
-LIBS += -lportaudio
+DEFINES += USE_SPEEX USE_KISSFFT
INCLUDEPATH += \
ext/rubberband \
@@ 65,18 63,18 @@ BQ_SOURCES += \
ext/bqaudiostream/src/AudioStreamExceptions.cpp
win32-msvc* {
- DEFINES += HAVE_MEDIAFOUNDATION _USE_MATH_DEFINES
- LIBS += -lmfplat -lmfreadwrite -lmfuuid -lpropsys -ladvapi32 -lwinmm -lws2_32
+ DEFINES += HAVE_PORAUDIO HAVE_MEDIAFOUNDATION _USE_MATH_DEFINES
+ LIBS += -lportaudio -lmfplat -lmfreadwrite -lmfuuid -lpropsys -ladvapi32 -lwinmm -lws2_32
}
macx* {
- DEFINES += HAVE_COREAUDIO HAVE_VDSP USE_PTHREADS
- LIBS += -framework CoreAudio -framework CoreMidi -framework AudioUnit -framework AudioToolbox -framework CoreFoundation -framework CoreServices -framework Accelerate
+ DEFINES += HAVE_COREAUDIO HAVE_PORTAUDIO HAVE_VDSP USE_PTHREADS
+ LIBS += -lportaudio -framework CoreAudio -framework CoreMidi -framework AudioUnit -framework AudioToolbox -framework CoreFoundation -framework CoreServices -framework Accelerate
}
linux* {
- DEFINES += HAVE_SNDFILE USE_PTHREADS
- LIBS += -lsndfile
+ DEFINES += HAVE_SNDFILE HAVE_LIBPULSE USE_PTHREADS
+ LIBS += -lsndfile -lpulse
}
for (file, BQ_SOURCES) { SOURCES += $$file }
M src/Interface.cpp +30 -0
@@ 6,6 6,8 @@
#include "Processor.h"
#include <QFileDialog>
+#include <QGridLayout>
+#include <QPushButton>
#include <QMessageBox>
#include <bqaudiostream/AudioReadStreamFactory.h>
@@ 16,6 18,32 @@ Interface::Interface(Processor *p, QWidg
QMainWindow(parent),
m_processor(p)
{
+ auto mainFrame = new QFrame;
+ auto mainLayout = new QGridLayout;
+ mainFrame->setLayout(mainLayout);
+
+ auto open = new QPushButton(tr("Open"));
+ mainLayout->addWidget(open, 0, 0);
+
+ auto rewind = new QPushButton(tr("<<"));
+ mainLayout->addWidget(rewind, 0, 1);
+
+ auto play = new QPushButton(tr(">"));
+ mainLayout->addWidget(play, 0, 2);
+
+ auto pause = new QPushButton(tr("||"));
+ mainLayout->addWidget(pause, 0, 3);
+
+ connect(open, SIGNAL(clicked()), this, SLOT(open()));
+ connect(rewind, SIGNAL(clicked()), this, SLOT(rewind()));
+ connect(play, SIGNAL(clicked()), this, SLOT(play()));
+ connect(pause, SIGNAL(clicked()), this, SLOT(pause()));
+
+ m_filenameLabel = new QLabel;
+ m_filenameLabel->setText(tr("<no file loaded>"));
+ mainLayout->addWidget(m_filenameLabel, 1, 0, 1, 4);
+
+ setCentralWidget(mainFrame);
}
Interface::~Interface()
@@ 47,11 75,13 @@ Interface::open(QString filename)
{
try {
m_processor->open(filename);
+ m_filenameLabel->setText(m_processor->getTrackName());
} catch (const exception &f) {
QMessageBox::critical
(this, tr("Failed to open file"),
tr("Could not open audio file \"%1\": %2")
.arg(filename).arg(QString::fromUtf8(f.what())));
+ m_filenameLabel->setText(tr("<no file loaded>"));
}
}
M src/Interface.h +1 -0
@@ 37,6 37,7 @@ protected slots:
private:
Processor *m_processor;
QDoubleSpinBox *m_speedSpin;
+ QLabel *m_filenameLabel;
};
M src/Processor.cpp +41 -40
@@ 119,6 119,14 @@ Processor::getFilename() const
return m_filename;
}
+QString
+Processor::getTrackName() const
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_trackName != "") return m_trackName;
+ else return QFileInfo(m_filename).baseName();
+}
+
int
Processor::getSampleRate() const
{
@@ 345,8 353,6 @@ Processor::FileReadThread::run()
while (m_status == Working) {
- //!!! this should be a call out to a function in m_processor
-
float *newBlock = 0;
try {
@@ 456,12 462,12 @@ Processor::open(QString filename)
m_stretcher->setMaxProcessSize(m_blockSize);
- m_stretchIn = new float *[m_stretcher->getChannelCount()];
+ m_stretchIn = new float *[m_blocks.channels];
- for (int c = 0; c < (int)m_stretcher->getChannelCount(); ++c) {
+ for (int c = 0; c < m_blocks.channels; ++c) {
m_stretchIn[c] = new float[m_blockSize];
}
- m_stretchOutPtrs = new float *[m_stretcher->getChannelCount()];
+ m_stretchOutPtrs = new float *[m_blocks.channels];
m_fileReadThread = new FileReadThread(this, &m_blocks, m_rs);
m_fileReadThread->start();
@@ 637,11 643,18 @@ Processor::getSourceSamples(float *const
windowSort = 2;
}
- if (m_windowSort != windowSort ||
- m_centreFocus != m_lastCentreFocus ||
- !m_stretcher ||
- nchannels || m_stretcher->getChannelCount()) {
+ // We always run the stretcher with m_blocks.channels, the channel
+ // count of the source file. But nchannels, the channel count of
+ // the audio device, may differ. We could mix down later after
+ // stretching (though actually we just discard/silence excess
+ // channels).
+
+ if (!m_stretcher ||
+ m_windowSort != windowSort ||
+ m_centreFocus != m_lastCentreFocus) {
+
delete m_stretcher;
+
RubberBandStretcher::Options options =
RubberBandStretcher::OptionProcessRealTime |
RubberBandStretcher::OptionTransientsCrisp |
@@ 652,7 665,8 @@ Processor::getSourceSamples(float *const
if (m_centreFocus) options |= RubberBandStretcher::OptionChannelsTogether;
m_stretcher = new RubberBandStretcher
- (m_blocks.sampleRate, nchannels, options, timeRatio, pitchScale);
+ (m_blocks.sampleRate, m_blocks.channels,
+ options, timeRatio, pitchScale);
m_windowSort = windowSort;
}
@@ 665,6 679,8 @@ Processor::getSourceSamples(float *const
m_lastCentreFocus = m_centreFocus;
+ int fileChannels = m_blocks.channels;
+
// We de-interleave the audio data and write the input for the
// stretcher into m_stretchIn. m_blockSize is an arbitrary size
// which is both the number of interleaved frames in each block of
@@ 672,11 688,9 @@ Processor::getSourceSamples(float *const
// the maximum we can de-interleave and feed in any one chunk.
int done = 0;
- int fileChannels = m_blocks.channels;
-
while (done < (int)nframes) {
-// cout << "getSourceSamples: nframes = "<< nframes << ", done = " << done << ", m_processBlock = " << m_processBlock << ", blocks = " << m_blocks.blocks.size() << endl;
+// cout << "getSourceSamples: nframes = "<< nframes << ", done = " << done << ", m_processBlock = " << m_processBlock << ", blocks = " << m_blocks.blocks.size() << ", m_blockSize = " << m_blockSize << endl;
int available = m_stretcher->available();
if (available < 0) break;
@@ 721,47 735,27 @@ Processor::getSourceSamples(float *const
m_playing = false;
emit playEnded();
}
-
- // nchannels is the number of channels required for output
- // to the audio device. This value came directly from the
- // device handler, and the stretcher has been configured
- // with a matching channel count. fileChannels is the
- // number in the audio file, which may differ. We always
- // run the stretcher at the audio device channel count.
-
- for (int c = 0; c < nchannels && c < fileChannels; ++c) {
+
+ for (int c = 0; c < fileChannels; ++c) {
for (int i = 0; i < toProcess; ++i) {
m_stretchIn[c][i] = source[(i * fileChannels) + c];
}
}
- for (int c = fileChannels; c < nchannels; ++c) {
- if (c > 0) {
- // excess channels on audio output: duplicate the
- // first file channel for them (an arbitrary decision)
- for (int i = 0; i < toProcess; ++i) {
- m_stretchIn[c][i] = m_stretchIn[0][i];
- }
- } else {
- // zero channels in the file!
- for (int i = 0; i < toProcess; ++i) {
- m_stretchIn[c][i] = 0.f;
- }
- }
- }
-
m_stretcher->process(m_stretchIn, toProcess, false);
}
int count = m_stretcher->available();
if (count == 0) continue;
- if (count > ((int)nframes - done)) count = (int)nframes - done;
+ if (count > ((int)nframes - done)) {
+ count = (int)nframes - done;
+ }
// m_stretchOutPtrs is a set of temporary pointers indicating
// where to write the output to, as a set of offsets into the
// desired samples arrays
- for (int c = 0; c < nchannels; ++c) {
+ for (int c = 0; c < fileChannels && c < nchannels; ++c) {
m_stretchOutPtrs[c] = samples[c] + done;
}
@@ 769,7 763,14 @@ Processor::getSourceSamples(float *const
done += count;
}
- // any excess should be filled up with zero samples
+ // fill excess channels with zeroes
+ for (int c = fileChannels; c < nchannels; ++c) {
+ for (int i = 0; i < (int)nframes; ++i) {
+ samples[c][i] = 0.f;
+ }
+ }
+
+ // and fill excess samples with zeroes (should only happen at end of file)
for (int c = 0; c < nchannels; ++c) {
for (int i = done; i < (int)nframes; ++i) {
samples[c][i] = 0.f;
M src/Processor.h +3 -1
@@ 46,6 46,7 @@ public:
void cancelFileLoad();
QString getFilename() const;
+ QString getTrackName() const;
int getSampleRate() const;
int getChannelCount() const;
@@ 110,6 111,7 @@ public slots:
protected:
QString m_filename;
+ QString m_trackName;
breakfastquay::SystemPlaybackTarget *m_target;
RubberBand::RubberBandStretcher *m_stretcher;
@@ 120,7 122,7 @@ protected:
mutable QMutex m_mutex;
- int m_blockSize;
+ const int m_blockSize;
struct BlockRec {
BlockRec(int rate, int c, int bs) :