cannam@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@0
|
2
|
cannam@0
|
3 #ifdef HAVE_PORTAUDIO
|
cannam@0
|
4
|
cannam@0
|
5 #include "AudioPortAudioSource.h"
|
cannam@0
|
6 #include "AudioCallbackRecordTarget.h"
|
cannam@0
|
7
|
cannam@0
|
8 #include <iostream>
|
cannam@0
|
9 #include <cassert>
|
cannam@0
|
10 #include <cmath>
|
cannam@0
|
11
|
cannam@0
|
12 //#define DEBUG_AUDIO_PORT_AUDIO_SOURCE 1
|
cannam@0
|
13
|
cannam@0
|
14 AudioPortAudioSource::AudioPortAudioSource(AudioCallbackRecordTarget *target) :
|
cannam@0
|
15 AudioCallbackRecordSource(target),
|
cannam@0
|
16 m_stream(0),
|
cannam@0
|
17 m_bufferSize(0),
|
cannam@0
|
18 m_sampleRate(0),
|
cannam@0
|
19 m_latency(0)
|
cannam@0
|
20 {
|
cannam@0
|
21 PaError err;
|
cannam@0
|
22
|
cannam@0
|
23 err = Pa_Initialize();
|
cannam@0
|
24 if (err != paNoError) {
|
cannam@0
|
25 std::cerr << "ERROR: AudioPortAudioSource: Failed to initialize PortAudio" << std::endl;
|
cannam@0
|
26 return;
|
cannam@0
|
27 }
|
cannam@0
|
28
|
cannam@0
|
29 m_bufferSize = 1024;
|
cannam@0
|
30 m_sampleRate = 44100;
|
cannam@0
|
31 if (m_target && (m_target->getPreferredSampleRate() != 0)) {
|
cannam@0
|
32 m_sampleRate = m_target->getPreferredSampleRate();
|
cannam@0
|
33 }
|
cannam@0
|
34
|
cannam@0
|
35 m_latency = Pa_GetMinNumBuffers(m_bufferSize, m_sampleRate) * m_bufferSize;
|
cannam@0
|
36
|
cannam@0
|
37 err = Pa_OpenDefaultStream(&m_stream, m_target->getChannelCount(),
|
cannam@0
|
38 0, paFloat32,
|
cannam@0
|
39 m_sampleRate, m_bufferSize, 0,
|
cannam@0
|
40 processStatic, this);
|
cannam@0
|
41
|
cannam@0
|
42 if (err != paNoError) {
|
cannam@0
|
43 std::cerr << "ERROR: AudioPortAudioSource: Failed to open PortAudio stream" << std::endl;
|
cannam@0
|
44 m_stream = 0;
|
cannam@0
|
45 Pa_Terminate();
|
cannam@0
|
46 return;
|
cannam@0
|
47 }
|
cannam@0
|
48
|
cannam@0
|
49 err = Pa_StartStream(m_stream);
|
cannam@0
|
50
|
cannam@0
|
51 if (err != paNoError) {
|
cannam@0
|
52 std::cerr << "ERROR: AudioPortAudioSource: Failed to start PortAudio stream" << std::endl;
|
cannam@0
|
53 Pa_CloseStream(m_stream);
|
cannam@0
|
54 m_stream = 0;
|
cannam@0
|
55 Pa_Terminate();
|
cannam@0
|
56 return;
|
cannam@0
|
57 }
|
cannam@0
|
58
|
cannam@0
|
59 if (m_target) {
|
cannam@0
|
60 std::cerr << "AudioPortAudioSource: block size " << m_bufferSize << std::endl;
|
cannam@0
|
61 m_target->setSourceBlockSize(m_bufferSize);
|
cannam@0
|
62 m_target->setSourceSampleRate(m_sampleRate);
|
cannam@0
|
63 m_target->setSourceRecordLatency(m_latency);
|
cannam@0
|
64 }
|
cannam@0
|
65 }
|
cannam@0
|
66
|
cannam@0
|
67 AudioPortAudioSource::~AudioPortAudioSource()
|
cannam@0
|
68 {
|
cannam@0
|
69 if (m_stream) {
|
cannam@0
|
70 PaError err;
|
cannam@0
|
71 err = Pa_CloseStream(m_stream);
|
cannam@0
|
72 if (err != paNoError) {
|
cannam@0
|
73 std::cerr << "ERROR: AudioPortAudioSource: Failed to close PortAudio stream" << std::endl;
|
cannam@0
|
74 }
|
cannam@0
|
75 Pa_Terminate();
|
cannam@0
|
76 }
|
cannam@0
|
77 }
|
cannam@0
|
78
|
cannam@0
|
79 bool
|
cannam@0
|
80 AudioPortAudioSource::isOK() const
|
cannam@0
|
81 {
|
cannam@0
|
82 return (m_stream != 0);
|
cannam@0
|
83 }
|
cannam@0
|
84
|
cannam@0
|
85 int
|
cannam@0
|
86 AudioPortAudioSource::processStatic(void *input, void *output,
|
cannam@0
|
87 unsigned long nframes,
|
cannam@0
|
88 PaTimestamp outTime, void *data)
|
cannam@0
|
89 {
|
cannam@0
|
90 return ((AudioPortAudioSource *)data)->process(input, output,
|
cannam@0
|
91 nframes, outTime);
|
cannam@0
|
92 }
|
cannam@0
|
93
|
cannam@0
|
94 int
|
cannam@0
|
95 AudioPortAudioSource::process(void *inputBuffer,
|
cannam@0
|
96 void *outputBuffer,
|
cannam@0
|
97 unsigned long nframes,
|
cannam@0
|
98 PaTimestamp)
|
cannam@0
|
99 {
|
cannam@0
|
100 #ifdef DEBUG_AUDIO_PORT_AUDIO_SOURCE
|
cannam@0
|
101 std::cout << "AudioPortAudioSource::process(" << nframes << ")" << std::endl;
|
cannam@0
|
102 #endif
|
cannam@0
|
103
|
cannam@0
|
104 if (!m_target) return 0;
|
cannam@0
|
105
|
cannam@0
|
106 float *input = (float *)inputBuffer;
|
cannam@0
|
107
|
cannam@0
|
108 assert(nframes <= m_bufferSize);
|
cannam@0
|
109
|
cannam@0
|
110 static float **tmpbuf = 0;
|
cannam@0
|
111 static size_t tmpbufch = 0;
|
cannam@0
|
112 static size_t tmpbufsz = 0;
|
cannam@0
|
113
|
cannam@0
|
114 size_t channels = m_target->getChannelCount();
|
cannam@0
|
115
|
cannam@0
|
116 if (!tmpbuf || tmpbufch != channels || tmpbufsz < m_bufferSize) {
|
cannam@0
|
117
|
cannam@0
|
118 if (tmpbuf) {
|
cannam@0
|
119 for (size_t i = 0; i < tmpbufch; ++i) {
|
cannam@0
|
120 delete[] tmpbuf[i];
|
cannam@0
|
121 }
|
cannam@0
|
122 delete[] tmpbuf;
|
cannam@0
|
123 }
|
cannam@0
|
124
|
cannam@0
|
125 tmpbufch = channels;
|
cannam@0
|
126 tmpbufsz = m_bufferSize;
|
cannam@0
|
127 tmpbuf = new float *[tmpbufch];
|
cannam@0
|
128
|
cannam@0
|
129 for (size_t i = 0; i < tmpbufch; ++i) {
|
cannam@0
|
130 tmpbuf[i] = new float[tmpbufsz];
|
cannam@0
|
131 }
|
cannam@0
|
132 }
|
cannam@0
|
133
|
cannam@0
|
134 float peakLeft = 0.0, peakRight = 0.0;
|
cannam@0
|
135
|
cannam@0
|
136 for (size_t ch = 0; ch < 2; ++ch) {
|
cannam@0
|
137
|
cannam@0
|
138 float peak = 0.0;
|
cannam@0
|
139
|
cannam@0
|
140 if (ch < channels) {
|
cannam@0
|
141
|
cannam@0
|
142 // PortAudio samples are interleaved
|
cannam@0
|
143 for (size_t i = 0; i < nframes; ++i) {
|
cannam@0
|
144 tmpbuf[ch][i] = input[i * 2 + ch];
|
cannam@0
|
145 float sample = fabsf(input[i * 2 + ch]);
|
cannam@0
|
146 if (sample > peak) peak = sample;
|
cannam@0
|
147 }
|
cannam@0
|
148
|
cannam@0
|
149 } else if (ch == 1 && channels == 1) {
|
cannam@0
|
150
|
cannam@0
|
151 for (size_t i = 0; i < nframes; ++i) {
|
cannam@0
|
152 tmpbuf[0][i] = input[i * 2 + ch];
|
cannam@0
|
153 float sample = fabsf(input[i * 2 + ch]);
|
cannam@0
|
154 if (sample > peak) peak = sample;
|
cannam@0
|
155 }
|
cannam@0
|
156
|
cannam@0
|
157 } else {
|
cannam@0
|
158 for (size_t i = 0; i < nframes; ++i) {
|
cannam@0
|
159 tmpbuf[ch][i] = 0;
|
cannam@0
|
160 }
|
cannam@0
|
161 }
|
cannam@0
|
162
|
cannam@0
|
163 if (ch == 0) peakLeft = peak;
|
cannam@0
|
164 if (ch > 0 || channels == 1) peakRight = peak;
|
cannam@0
|
165 }
|
cannam@0
|
166
|
cannam@0
|
167 m_target->putSamples(nframes, tmpbuf);
|
cannam@0
|
168 m_target->setInputLevels(peakLeft, peakRight);
|
cannam@0
|
169
|
cannam@0
|
170 return 0;
|
cannam@0
|
171 }
|
cannam@0
|
172
|
cannam@0
|
173 #endif /* HAVE_PORTAUDIO */
|
cannam@0
|
174
|