summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--audioio.cpp128
-rw-r--r--audioio.h21
-rw-r--r--debian/control2
-rw-r--r--tuner.cpp10
-rw-r--r--tuner.h3
-rw-r--r--tunerdemo.cpp16
7 files changed, 179 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index c6cd4e3..06328f0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,8 @@
+PORTAUDIOCFLAGS=$(shell pkg-config --cflags portaudiocpp)
+PORTAUDIOLIBS=$(shell pkg-config --libs portaudiocpp)
+
CXX=clang++-7
-CXXFLAGS=-stdlib=libc++ -Wall -O2 -std=c++17
+CXXFLAGS=-stdlib=libc++ -Wall -O2 -std=c++17 -fexceptions
#-march=native -mtune=native # is not better for llvm
# libstdc++-8 doesn't have transform_reduce
@@ -12,8 +15,8 @@ PREFIX=/usr/local/bin
all: tunerdemo testsuite
-tunerdemo: util.o fft.o autocorrelation.o tuner.o tunerdemo.o
- $(CXX) $(CXXFLAGS) -o $@ $^
+tunerdemo: audioio.o util.o fft.o autocorrelation.o tuner.o tunerdemo.o
+ $(CXX) $(CXXFLAGS) $(PORTAUDIOLIBS) -o $@ $^
testsuite: util.o fft.o autocorrelation.o tuner.o testsuite.o
$(CXX) $(CXXFLAGS) -o $@ $^
@@ -30,6 +33,9 @@ tuner.o: tuner.cpp tuner.h
util.o: util.cpp util.h
$(CXX) $(CXXFLAGS) -c -o $@ $<
+audioio.o: audioio.cpp audioio.h
+ $(CXX) $(CXXFLAGS) $(PORTAUDIOCFLAGS) -c -o $@ $<
+
testsuite.o: testsuite.cpp fft.h autocorrelation.h tuner.h
$(CXX) $(CXXFLAGS) -c -o $@ $<
diff --git a/audioio.cpp b/audioio.cpp
new file mode 100644
index 0000000..31fa1cd
--- /dev/null
+++ b/audioio.cpp
@@ -0,0 +1,128 @@
+#include "audioio.h"
+
+#include <exception>
+#include <iostream>
+
+#include <portaudiocpp/AutoSystem.hxx>
+#include <portaudiocpp/CallbackInterface.hxx>
+#include <portaudiocpp/Device.hxx>
+#include <portaudiocpp/InterfaceCallbackStream.hxx>
+#include <portaudiocpp/StreamParameters.hxx>
+#include <portaudiocpp/System.hxx>
+#include <portaudiocpp/SystemDeviceIterator.hxx>
+
+namespace {
+
+class Callback: public portaudio::CallbackInterface {
+ public:
+ Callback(int size): mBuffer(size){}
+
+ std::vector<std::complex<double>> mBuffer;
+
+ int paCallbackFun( const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags ) override
+ {
+ std::cout << "Callback" << std::endl;
+
+ float* buf = (float*)inputBuffer;
+ for (int i = 0; i < framesPerBuffer; i++) {
+ mBuffer[i] = buf[i];
+ }
+ return 0;
+ }
+};
+
+int bufferSizeFromSampleRate(double sampleRate) {
+ int result = 1;
+
+ while (result < sampleRate)
+ result <<= 1;
+
+ result /= 32;
+
+ if (result < 1024)
+ throw std::runtime_error(std::string("Bad buffer size ") + std::to_string(result) + " for sample rate " + std::to_string(sampleRate));
+
+ return result;
+}
+
+void printDeviceList() {
+ portaudio::System& mSystem = portaudio::System::instance();
+
+ std::cout << "Number of Devices: " << mSystem.deviceCount() << std::endl;
+ std::for_each(mSystem.devicesBegin(), mSystem.devicesEnd(),
+ [](const portaudio::Device& device){ std::cout
+ << "Device Name: " << device.name()
+ << " Default Rate: " << device.defaultSampleRate()
+ << std::endl;
+ }
+ );
+}
+
+} // namespace
+
+struct RIT::AudioIO::Impl {
+ Impl()
+ : mAudioSystem()
+ , mSystem(portaudio::System::instance())
+ , mDevice(mSystem.defaultInputDevice())
+ , mSampleRate(mDevice.defaultSampleRate())
+ , mSize(bufferSizeFromSampleRate(mSampleRate))
+ , mInputParams(mDevice, 1, portaudio::FLOAT32, false, mDevice.defaultLowInputLatency(), nullptr)
+ , mOutputParams(portaudio::System::nullDevice(), 0, portaudio::FLOAT32, false, mDevice.defaultLowInputLatency(), nullptr)
+ , mParameters(mInputParams, mOutputParams, mSampleRate, mSize, paNoFlag)
+ , mCallback(mSize)
+ , mStream(mParameters, mCallback)
+ {
+ printDeviceList();
+
+ mStream.start();
+
+ if (!mStream.isOpen())
+ throw std::runtime_error("Error: Stream not open");
+
+ if (!mStream.isActive())
+ throw std::runtime_error("Error: Stream not active");
+
+ std::cout << "Activated Device: " << mDevice.name() << " at " << mSampleRate << " Hz, buffer: " << mSize << " samples, running..." << std::endl;
+ }
+ ~Impl() {}
+
+ // Port audio specific
+ portaudio::AutoSystem mAudioSystem; // init / deinit portaudio
+ portaudio::System& mSystem;
+ portaudio::Device& mDevice;
+ double mSampleRate;
+ int mSize;
+ portaudio::DirectionSpecificStreamParameters mInputParams;
+ portaudio::DirectionSpecificStreamParameters mOutputParams;
+ portaudio::StreamParameters mParameters;
+ Callback mCallback;
+ portaudio::InterfaceCallbackStream mStream;
+};
+
+RIT::AudioIO::AudioIO(): mImpl(std::make_unique<AudioIO::Impl>())
+{
+}
+
+RIT::AudioIO::~AudioIO()
+{
+}
+
+std::vector<std::complex<double>> RIT::AudioIO::sample()
+{
+ return mImpl->mCallback.mBuffer; // TODO: thread synchronization! Ringbuffer? PaUtilRingBuffer?
+}
+
+int RIT::AudioIO::size() const
+{
+ return mImpl->mSize;
+}
+
+int RIT::AudioIO::sampleFrequency() const
+{
+ return int(mImpl->mSampleRate);
+}
+
diff --git a/audioio.h b/audioio.h
new file mode 100644
index 0000000..0200964
--- /dev/null
+++ b/audioio.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <complex>
+#include <vector>
+
+namespace RIT {
+
+class AudioIO {
+public:
+ AudioIO();
+ ~AudioIO();
+ std::vector<std::complex<double>> sample();
+ int size() const;
+ int sampleFrequency() const;
+
+private:
+ struct Impl;
+ std::unique_ptr<Impl> mImpl;
+};
+
+} // namespace RIT
diff --git a/debian/control b/debian/control
index 4107bec..e89c3a3 100644
--- a/debian/control
+++ b/debian/control
@@ -1,2 +1,2 @@
Package: rit-fft
-Depends: g++, clang
+Build-Depends: g++, clang, portaudio19-dev
diff --git a/tuner.cpp b/tuner.cpp
index 3013390..9e1f4b5 100644
--- a/tuner.cpp
+++ b/tuner.cpp
@@ -56,3 +56,13 @@ RIT::Pitch RIT::Tuner::operator() (const std::vector<std::complex<double>> &v)
return Pitch{};
}
+
+double RIT::Tuner::fMin()
+{
+ return double(mImpl->m_f_sample) / mImpl->mSize / 2;
+}
+
+double RIT::Tuner::fMax()
+{
+ return double(mImpl->m_f_sample);
+}
diff --git a/tuner.h b/tuner.h
index df17c0f..f5cb5e4 100644
--- a/tuner.h
+++ b/tuner.h
@@ -18,6 +18,9 @@ public:
Tuner(int size, int f_sample);
~Tuner();
+ double fMin();
+ double fMax();
+
Pitch operator() (const std::vector<std::complex<double>> &v);
private:
diff --git a/tunerdemo.cpp b/tunerdemo.cpp
index e70afb2..9a1f70b 100644
--- a/tunerdemo.cpp
+++ b/tunerdemo.cpp
@@ -1,23 +1,21 @@
#include "tuner.h"
+#include "audioio.h"
+
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
-const int sampleFrequency = 44100;
-const int fftSize = 4096;
+int main(int argc, char* argv[]) {
+ RIT::AudioIO audioIO;
-std::vector<std::complex<double>> sample()
-{
- return std::vector<std::complex<double>>(fftSize, 0.0);
-}
+ RIT::Tuner tuner(audioIO.size(), audioIO.sampleFrequency());
-int main(int argc, char* argv[]) {
- RIT::Tuner tuner(fftSize, sampleFrequency);
+ std::cout << "Tuner range: " << tuner.fMin() << " ... " << tuner.fMax() << " Hz" << std::endl;
- std::vector<std::complex<double>> dataIn = sample();
+ std::vector<std::complex<double>> dataIn = audioIO.sample();
while (true) {
auto start = std::chrono::high_resolution_clock::now();