summaryrefslogtreecommitdiffhomepage
path: root/audioio.cpp
blob: 31fa1cda1bec51e16fb2f227613fcaa60b1cdef5 (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
#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);
}