This repository has been archived by the owner on Feb 5, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalsa.c
164 lines (147 loc) · 5.9 KB
/
alsa.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
// input: ALSA
#include "alsa.h"
#include "debug.h"
#include "common.h"
#include <alloca.h>
#include <alsa/asoundlib.h>
#include <math.h>
// assuming stereo
#define CHANNELS_COUNT 2
#define SAMPLE_RATE 44100
static void initialize_audio_parameters(snd_pcm_t **handle, struct audio_data *audio,
snd_pcm_uframes_t *frames) {
// alsa: open device to capture audio
int err = snd_pcm_open(handle, audio->source, SND_PCM_STREAM_CAPTURE, 0);
if (err < 0) {
fprintf(stderr, "error opening stream: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
} else
debug("open stream successful\n");
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(¶ms); // assembling params
snd_pcm_hw_params_any(*handle, params); // setting defaults or something
// interleaved mode right left right left
snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
// trying to set 16bit
snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(*handle, params, CHANNELS_COUNT);
unsigned int sample_rate = SAMPLE_RATE;
// trying our rate
snd_pcm_hw_params_set_rate_near(*handle, params, &sample_rate, NULL);
// number of frames pr read
snd_pcm_hw_params_set_period_size_near(*handle, params, frames, NULL);
err = snd_pcm_hw_params(*handle, params); // attempting to set params
if (err < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_prepare(*handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
// getting actual format
snd_pcm_hw_params_get_format(params, (snd_pcm_format_t *)&sample_rate);
// converting result to number of bits
if (sample_rate <= 5)
audio->format = 16;
else if (sample_rate <= 9)
audio->format = 24;
else
audio->format = 32;
snd_pcm_hw_params_get_rate(params, &audio->rate, NULL);
snd_pcm_hw_params_get_period_size(params, frames, NULL);
// snd_pcm_hw_params_get_period_time(params, &sample_rate, &dir);
}
static int get_certain_frame(signed char *buffer, int buffer_index, int adjustment) {
// using the 10 upper bits this would give me a vert res of 1024, enough...
int temp = buffer[buffer_index + adjustment - 1] << 2;
int lo = buffer[buffer_index + adjustment - 2] >> 6;
if (lo < 0)
lo = abs(lo) + 1;
if (temp >= 0)
temp += lo;
else
temp -= lo;
return temp;
}
/*
static void fill_audio_outs(struct audio_data* audio, signed char* buffer,
const int size) {
int radj = audio->format / 4; // adjustments for interleaved
int ladj = audio->format / 8;
static int audio_out_buffer_index = 0;
// sorting out one channel and only biggest octet
for (int buffer_index = 0; buffer_index < size; buffer_index += ladj * 2) {
// first channel
int tempr = get_certain_frame(buffer, buffer_index, radj);
// second channel
int templ = get_certain_frame(buffer, buffer_index, ladj);
// mono: adding channels and storing it in the buffer
if (audio->channels == 1)
audio->audio_out_l[audio_out_buffer_index] = (templ + tempr) / 2;
else { // stereo storing channels in buffer
audio->audio_out_l[audio_out_buffer_index] = templ;
audio->audio_out_r[audio_out_buffer_index] = tempr;
}
++audio_out_buffer_index;
audio_out_buffer_index %= audio->FFTbufferSize;
}
}
*/
void *input_alsa(void *data) {
int err;
struct audio_data *audio = (struct audio_data *)data;
snd_pcm_t *handle;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
snd_pcm_uframes_t frames = audio->input_buffer_size / 2;
initialize_audio_parameters(&handle, audio, &frames);
snd_pcm_get_params(handle, &buffer_size, &period_size);
int radj = audio->format / 4; // adjustments for interleaved
int ladj = audio->format / 8;
int16_t buf[period_size];
int32_t buffer32[period_size];
frames = period_size / ((audio->format / 8) * CHANNELS_COUNT);
// printf("period size: %lu\n", period_size);
// exit(0);
// frames * bits/8 * channels
// const int size = frames * (audio->format / 8) * CHANNELS_COUNT;
signed char *buffer = malloc(period_size);
while (!audio->terminate) {
switch (audio->format) {
case 16:
err = snd_pcm_readi(handle, buf, frames);
break;
case 32:
err = snd_pcm_readi(handle, buffer32, frames);
for (uint16_t i = 0; i < frames * 2; i++) {
buf[i] = buffer32[i] / pow(2, 16);
}
break;
default:
err = snd_pcm_readi(handle, buffer, frames);
// sorting out one channel and only biggest octet
for (uint16_t i = 0; i < period_size * 2; i += ladj * 2) {
// first channel
buf[i] = get_certain_frame(buffer, i, ladj);
// second channel
buf[i + 1] = get_certain_frame(buffer, i, radj);
}
// fill_audio_outs(audio, buffer, period_size);
break;
}
if (err == -EPIPE) {
/* EPIPE means overrun */
debug("overrun occurred\n");
snd_pcm_prepare(handle);
} else if (err < 0) {
debug("error from read: %s\n", snd_strerror(err));
} else if (err != (int)frames) {
debug("short read, read %d %d frames\n", err, (int)frames);
}
write_to_input_buffers(frames * CHANNELS_COUNT, buf, data);
}
free(buffer);
snd_pcm_close(handle);
return NULL;
}