diff options
author | Roland Stigge <stigge@antcom.de> | 2019-02-17 22:10:33 +0100 |
---|---|---|
committer | Roland Stigge <stigge@antcom.de> | 2019-02-17 22:10:33 +0100 |
commit | eac187fcbafcc518185d1074395c5fbe6a7e5aec (patch) | |
tree | b3585f50f9db0a04fd3e5c781eb9f952e39e4a53 | |
parent | 308a53c389cdc2631860f434989cd57efbf91145 (diff) |
Added portaudio support
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | audioio.cpp | 128 | ||||
-rw-r--r-- | audioio.h | 21 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | tuner.cpp | 10 | ||||
-rw-r--r-- | tuner.h | 3 | ||||
-rw-r--r-- | tunerdemo.cpp | 16 |
7 files changed, 179 insertions, 13 deletions
@@ -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 @@ -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); +} @@ -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(); |