-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdu3.c
180 lines (124 loc) · 5.49 KB
/
du3.c
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#define SAMPLE_FORMAT ma_format_s16
#define CHANNELS 1
#define SAMPLE_RATE 44100
#define BUFFER_SIZE (int)(SAMPLE_RATE * CHANNELS * 2) // Adjust the buffer size as needed
//######################################################
// TODO:
// - fadein/out
// - Multitrack
// - mute
// - audiouffer loopover
// - overdubbing
int16_t audioBuffer[BUFFER_SIZE];
ma_uint64 audioBufferPos = 0;
ma_bool32 isRecording = MA_FALSE; // Flag to indicate whether recording is active
ma_bool32 isSTOP = MA_FALSE; // Flag to indicate whether recording is active
ma_uint64 firstNonSilent = 0;
ma_uint64 lastNonSilent = BUFFER_SIZE - 1;
ma_uint64 lengthRecordBuffer = 0;
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
MA_ASSERT(pDevice->capture.format == pDevice->playback.format);
MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels);
if (isRecording) {
const int16_t* pInputS16 = (const int16_t*)pInput; // Assuming the input is in 16-bit signed integer format
// Write the input audio samples to the global buffer
ma_uint64 bytesToCopy = frameCount * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint64 bytesAvailable = (BUFFER_SIZE - audioBufferPos) * sizeof(int16_t);
if (bytesToCopy > bytesAvailable || isSTOP) {
// If attempting to copy more data than available space in the buffer, copy only what fits
bytesToCopy = bytesAvailable;
isRecording = MA_FALSE; // Stop recording when the buffer is full
printf("Recording stopped. Buffer full.\n");
// Detect the first and last non-silent sample positions
for (ma_uint64 i = 0; i < lengthRecordBuffer; ++i) {
if (audioBuffer[i] > 80 || audioBuffer[i] < -80) {
firstNonSilent = i;
break;
}
}
for (ma_uint64 i = lengthRecordBuffer - 1; i > firstNonSilent; --i) {
if (audioBuffer[i] > 80 || audioBuffer[i] < -80) {
lastNonSilent = i;
break;
}
}
// Adjust the buffer position to play the non-silent section
audioBufferPos = firstNonSilent;
// printf("Audio Buffer:\n");
// for (ma_uint64 i = firstNonSilent; i < lastNonSilent; ++i) {
// printf("%d\n", audioBuffer[i]);
// }
}else{
// Copy input audio samples to the global buffer
memcpy(audioBuffer + audioBufferPos, pInputS16, bytesToCopy);
audioBufferPos += bytesToCopy / sizeof(int16_t);
lengthRecordBuffer += bytesToCopy;
}
}else{
ma_uint32 framesAvailable = BUFFER_SIZE - audioBufferPos;
ma_uint32 framesToWrite = frameCount > framesAvailable ? framesAvailable : frameCount;
if (framesToWrite > 0) {
MA_COPY_MEMORY(pOutput, audioBuffer + audioBufferPos, frameCount * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
audioBufferPos += framesToWrite;
}
// Cut off the last portion of the buffer during playback to avoid a pause
if (audioBufferPos >= lastNonSilent) {
audioBufferPos = firstNonSilent; // Reset the buffer position to create a continuous loop
}
}
}
int main() {
static struct termios oldt, newt;
ma_result result;
ma_device_config deviceConfig;
ma_device device;
deviceConfig = ma_device_config_init(ma_device_type_duplex);
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_s16;
deviceConfig.capture.channels = 1;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_s16;
deviceConfig.playback.channels = 1;
deviceConfig.dataCallback = data_callback;
result = ma_device_init(NULL, &deviceConfig, &device);
if (result != MA_SUCCESS) {
return result;
}
ma_device_start(&device);
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr( STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
printf("Ready!...\n");
int c;
while((c=getchar())!= 'q'){
if( c == '1' && isRecording == MA_FALSE){
printf("RECORDING TRACK 1\n");
isRecording = MA_TRUE;
}else if( c == '1' && isRecording == MA_TRUE){
printf("STOPPED RECORDING TRACK 1\n");
isSTOP = MA_TRUE;
}
}
printf("Playback...\n");
printf("Press Enter to quit...");
getchar();
// Uninitialize the sound and device
ma_device_uninit(&device);
/*restore the old settings*/
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}