summaryrefslogtreecommitdiffhomepage
path: root/audioio.cpp
blob: f24a0fd84ca343448be3c87d1a5e3535f8d4ecab (plain)
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
126
127
128
129
130
#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
		{
			float* buf = (float*)inputBuffer;
			std::cout << "Callback " << std::endl;

			for (int i = 0; i < framesPerBuffer; i++) {
				//if (buf[i] > 0.1)
				//	std::cout << "DEBUG: " << buf[i] << std::endl;
				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
}

int RIT::AudioIO::size() const
{
	return mImpl->mSize;
}

int RIT::AudioIO::sampleFrequency() const
{
	return int(mImpl->mSampleRate);
}