-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdsp.cpp
More file actions
155 lines (130 loc) · 5.06 KB
/
dsp.cpp
File metadata and controls
155 lines (130 loc) · 5.06 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <iostream>
#include <cmath>
#include <csignal>
#include <atomic>
#include <thread>
#include <chrono>
#include <fstream>
#include <rtaudio/RtAudio.h>
#include "config.h"
#include "delayBuffer.h"
typedef struct {
float minDynamic;
float dynamicRange;
float maxVolume;
float smoothing;
float lookaheadDelay;
float averagingWindow;
float gateLevel;
} dspcfg_t;
dspcfg_t dspCfg;
// Level control
void levelControl(float *samples, unsigned int nFrames, float avgLevel, bool isMusicPlaying) {
static float volume = 1.0f;
if (isMusicPlaying) // Ignore chunks that are below gate threshold. This prevents level control from turning up volume in between songs.
volume = std::min(dspCfg.minDynamic/avgLevel + dspCfg.dynamicRange, dspCfg.maxVolume) * dspCfg.smoothing + volume * (1.0f-dspCfg.smoothing);
else
volume = std::min(volume, 1.0f); // cap volume at 1 when music is stopped, in case user decides to play a loud song after a soft one
for (unsigned int i = 0; i < nFrames * CHANNELS; ++i) {
samples[i] *= volume;
}
//std::cout << volume << " " << isMusicPlaying << std::endl;
}
int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double /*streamTime*/, RtAudioStreamStatus status, void *userData) {
if (status) std::cerr << "Stream underflow detected!" << std::endl;
float *out = static_cast<float *>(outputBuffer);
float *in = static_cast<float *>(inputBuffer);
static DelayBuffer delayBuffer(SAMPLE_HZ, CHUNK_FRAMES, dspCfg.lookaheadDelay, dspCfg.averagingWindow); // 1 second lookahead window
delayBuffer.delay(out, in, nFrames);
// DSP chain
levelControl(out, nFrames, delayBuffer.getAvgLevel(), delayBuffer.isMusicPlaying(dspCfg.gateLevel));
return 0;
}
std::atomic<bool> run(true);
void signalHandler(int) {
run = false;
}
int main() {
// Read DSP config from file, if present
std::ifstream dspCfgFile("/home/pi/caraudio/dsp.cfg", std::ifstream::in);
if (dspCfgFile.is_open()) {
std::cout << "Reading DSP config from dsp.cfg" << std::endl;
dspCfgFile
>> dspCfg.minDynamic
>> dspCfg.dynamicRange
>> dspCfg.maxVolume
>> dspCfg.smoothing
>> dspCfg.lookaheadDelay
>> dspCfg.averagingWindow
>> dspCfg.gateLevel;
}
// If DSP config file is absent, use default values
else {
std::cout << "No dsp.cfg found, using defaults" << std::endl;
dspCfg = {
.minDynamic = 2e-2f,
.dynamicRange = 0.5f,
.maxVolume = 4.0f,
.smoothing = 5e-3f,
.lookaheadDelay = 1.0,
.averagingWindow = 1.0,
.gateLevel = 1e-4f
};
}
dspCfgFile.close();
std::cout << "minDynamic = " << dspCfg.minDynamic << ", dynamicRange = " << dspCfg.dynamicRange << ", maxVolume = " << dspCfg.maxVolume << ", smoothing = " << dspCfg.smoothing << ", lookaheadDelay = " << dspCfg.lookaheadDelay << " s, averagingWindow = " << dspCfg.averagingWindow << " s, gateLevel = " << dspCfg.gateLevel << std::endl;
RtAudio audio;
if (audio.getDeviceCount() < 1) {
std::cerr << "No audio devices found!" << std::endl;
return 1;
}
// Find bluetooth loopback and line out devices
int loopbackId = -1, outputId = -1;
RtAudio::DeviceInfo info;
for (int i = 0; i < audio.getDeviceCount(); i++) {
info = audio.getDeviceInfo(i);
if (info.probed) {
std::cout << "Device " << i << ": " << info.name << std::endl;
if (info.name == "Monitor of Built-in Audio Analog Stereo") loopbackId = i;
if (info.name == "Built-in Audio Stereo") outputId = i;
}
}
//loopbackId = 2; //audio.getDefaultInputDevice();
//outputId = 1; //audio.getDefaultOutputDevice();
if (loopbackId == -1 || outputId == -1) {
std::cerr << "Could not find loopback and/or output device." << std::endl;
return 1;
}
std::cout << "Connecting to input device " << loopbackId << ", output device " << outputId << std::endl;
RtAudio::StreamParameters inParams, outParams;
inParams.deviceId = loopbackId;
inParams.nChannels = CHANNELS; // stereo
outParams.deviceId = outputId; // USB DAC
outParams.nChannels = CHANNELS;
unsigned int sampleRate = SAMPLE_HZ;
unsigned int chunkFrames = CHUNK_FRAMES;
try {
audio.openStream(
&outParams, &inParams, RTAUDIO_FLOAT32,
sampleRate, &chunkFrames, &audioCallback
);
audio.startStream();
}
catch (RtAudioError& e) {
std::cerr << e.getMessage() << std::endl;
return 1;
}
std::cout << "Streaming audio... Press Ctrl-C to quit." << std::endl;
while (run) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Shutting down DSP..." << std::endl;
try {
audio.stopStream();
}
catch (RtAudioError& e) {
std::cerr << e.getMessage() << std::endl;
}
if (audio.isStreamOpen()) audio.closeStream();
return 0;
}