From eac187fcbafcc518185d1074395c5fbe6a7e5aec Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 17 Feb 2019 22:10:33 +0100 Subject: Added portaudio support --- Makefile | 12 ++++-- audioio.cpp | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ audioio.h | 21 ++++++++++ debian/control | 2 +- tuner.cpp | 10 +++++ tuner.h | 3 ++ tunerdemo.cpp | 16 ++++---- 7 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 audioio.cpp create mode 100644 audioio.h 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +class Callback: public portaudio::CallbackInterface { + public: + Callback(int size): mBuffer(size){} + + std::vector> 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()) +{ +} + +RIT::AudioIO::~AudioIO() +{ +} + +std::vector> 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 +#include + +namespace RIT { + +class AudioIO { +public: + AudioIO(); + ~AudioIO(); + std::vector> sample(); + int size() const; + int sampleFrequency() const; + +private: + struct Impl; + std::unique_ptr 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> &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> &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 #include #include using namespace std::chrono_literals; -const int sampleFrequency = 44100; -const int fftSize = 4096; +int main(int argc, char* argv[]) { + RIT::AudioIO audioIO; -std::vector> sample() -{ - return std::vector>(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> dataIn = sample(); + std::vector> dataIn = audioIO.sample(); while (true) { auto start = std::chrono::high_resolution_clock::now(); -- cgit v1.2.3