git ssb

0+

cel / foostudio



Commit 35cb432082c1b56fa5ee0dd9cdac03381729b0c4

Add capture

cel committed on 10/27/2016, 1:26:15 AM
Parent: 136b6626641c9e133183b28786493cb06aa10b15

Files changed

README.mdchanged
foostudio.cchanged
tune.cchanged
tune.hchanged
README.mdView
@@ -20,8 +20,9 @@
2020 ## References
2121
2222 - http://nullprogram.com/blog/2014/12/23/
2323 - http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
24 +- /usr/share/doc/libasound2-dev/examples/pcm.c.gz
2425 - alsa-lib/test/pcm_min.c
2526
2627 [code-music-studio]: https://github.com/substack/code-music-studio
2728
foostudio.cView
@@ -10,11 +10,17 @@
1010 #include <unistd.h>
1111 #include "tune.h"
1212 #include "ccdl.h"
1313
14 +#define max(a,b) ((a) > (b) ? (a) : (b))
15 +#define min(a,b) ((a) < (b) ? (a) : (b))
16 +
1417 static unsigned int rate = 44100;
1518 static unsigned int channels = 1;
16-static unsigned int latency = 500000; /* ring buffer length in us */
19 +static unsigned int channels_in = 1;
20 +static unsigned int latency = 50000; /* ring buffer length in us */
21 +static int resample = 1; /* enable software resampling */
22 +
1723 static snd_pcm_format_t format = SND_PCM_FORMAT_FLOAT;
1824
1925 /*
2026 * Underrun and suspend recovery, from alsa-lib/test/pcm.c
@@ -42,10 +48,11 @@
4248
4349 /* generate(): adapted from generate_sine() from alsa-lib/test/pcm.c */
4450 static void generate(struct tune *tune,
4551 const snd_pcm_channel_area_t *areas,
46- snd_pcm_uframes_t offset,
47- int count, double *_phase)
52 + snd_pcm_uframes_t offset, int count,
53 + float *frames_in, snd_pcm_uframes_t count_in,
54 + double *_phase)
4855 {
4956 double phase = *_phase;
5057 double step = 1/(double)rate;
5158 unsigned char *samples[channels];
@@ -71,16 +78,18 @@
7178 samples[chn] += offset * steps[chn];
7279 }
7380
7481 /* fill the channel areas */
82 + size_t j = 0;
7583 while (count-- > 0) {
7684 union {
7785 float f;
7886 int i;
7987 } fval;
8088 int res, i;
8189 if (tune && tune->play) {
82- fval.f = tune->play(tune, phase);
90 + float frame_in = j <= count_in ? frames_in[j] : 0;
91 + fval.f = tune->play(tune, phase, frame_in);
8392 } else {
8493 fval.f = 0;
8594 }
8695 res = fval.i;
@@ -101,129 +110,180 @@
101110 /*
102111 if (phase >= max_phase)
103112 phase -= max_phase;
104113 */
114 + j++;
105115 }
106116 *_phase = phase;
107117 }
108118
119 +int pre_begin(snd_pcm_t *pcm, int *first, snd_pcm_uframes_t period_size) {
120 + int err;
121 + snd_pcm_state_t state = snd_pcm_state(pcm);
122 + snd_pcm_sframes_t avail;
109123
124 + if (state == SND_PCM_STATE_XRUN) {
125 + err = xrun_recovery(pcm, -EPIPE);
126 + if (err < 0) {
127 + errx(1, "XRUN recovery failed: %s", snd_strerror(err));
128 + }
129 + *first = 1;
130 + } else if (state == SND_PCM_STATE_SUSPENDED) {
131 + err = xrun_recovery(pcm, -ESTRPIPE);
132 + if (err < 0) {
133 + errx(1, "SUSPEND recovery failed: %s", snd_strerror(err));
134 + }
135 + }
136 + avail = snd_pcm_avail_update(pcm);
137 + if (avail < 0) {
138 + err = xrun_recovery(pcm, avail);
139 + if (err < 0) {
140 + errx(1, "avail update failed: %s", snd_strerror(err));
141 + }
142 + *first = 1;
143 + return 1;
144 + }
145 + if ((snd_pcm_uframes_t)avail < period_size) {
146 + if (*first) {
147 + *first = 0;
148 + err = snd_pcm_start(pcm);
149 + if (err < 0) {
150 + errx(1, "Start error: %s", snd_strerror(err));
151 + }
152 + } else {
153 + err = snd_pcm_wait(pcm, -1);
154 + if (err < 0) {
155 + if ((err = xrun_recovery(pcm, err)) < 0) {
156 + errx(1, "snd_pcm_wait error: %s", snd_strerror(err));
157 + }
158 + *first = 1;
159 + }
160 + }
161 + return 1;
162 + }
163 + return 0;
164 +}
165 +
110166 int main(int argc, char *argv[])
111167 {
112168 struct ccdl ccdl;
113169 int err;
114- snd_pcm_t *pcm_out;
170 + snd_pcm_t *pcm_out, *pcm_in;
115171 const char *src_fname = "tune.c";
116172 const char *device_out = "default";
173 + const char *device_in = "default";
117174
118175 if (argc > 1) src_fname = argv[1];
119176 if (argc > 2) device_out = argv[2];
177 + if (argc > 3) device_in = argv[3];
120178
121179 ccdl_init(&ccdl, src_fname, "TUNE");
122180
123181 if (ccdl_watch(&ccdl)) {
124182 errx(1, "ccdl_watch");
125183 }
126184
127- if ((err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
185 + err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0);
186 + if (err < 0) {
128187 warnx("Playback open error: %s", snd_strerror(err));
129188 return 1;
130189 }
131190
191 + err = snd_pcm_open(&pcm_in, device_in, SND_PCM_STREAM_CAPTURE, 0);
192 + if (err < 0) {
193 + warnx("Capture open error: %s", snd_strerror(err));
194 + return 1;
195 + }
196 +
132197 if ((err = snd_pcm_set_params(pcm_out,
133198 format,
134199 SND_PCM_ACCESS_MMAP_INTERLEAVED,
135200 channels,
136201 rate,
137- 1,
202 + resample,
138203 latency)) < 0) {
139204 warnx("Playback open error: %s", snd_strerror(err));
140205 return 1;
141206 }
142207
143- snd_pcm_uframes_t buffer_size;
144- snd_pcm_uframes_t period_size;
145- if ((err = snd_pcm_get_params(pcm_out, &buffer_size, &period_size)) < 0) {
208 + if ((err = snd_pcm_set_params(pcm_in,
209 + format,
210 + SND_PCM_ACCESS_MMAP_INTERLEAVED,
211 + channels_in,
212 + rate,
213 + resample,
214 + latency)) < 0) {
215 + warnx("Capture open error: %s", snd_strerror(err));
216 + return 1;
217 + }
218 +
219 + snd_pcm_uframes_t buffer_size, buffer_size_in;
220 + snd_pcm_uframes_t period_size, period_size_in, period_size_out;
221 + if ((err = snd_pcm_get_params(pcm_out, &buffer_size, &period_size_out)) < 0) {
146222 warnx("Playback get params error: %s", snd_strerror(err));
147223 return 1;
148224 }
225 + if ((err = snd_pcm_get_params(pcm_in, &buffer_size_in, &period_size_in)) < 0) {
226 + warnx("Capture get params error: %s", snd_strerror(err));
227 + return 1;
228 + }
229 + period_size = min(period_size_in, period_size_out);
149230
231 + /*
232 + if (period_size != period_size_in) {
233 + errx(1, "playback and capture have different period sizes: %u %u", (unsigned int)period_size, (unsigned int)period_size_in);
234 + }
235 + */
236 +
150237 double phase = 0;
151238 const snd_pcm_channel_area_t *my_areas;
152239 snd_pcm_uframes_t offset, frames, size;
153- snd_pcm_sframes_t avail, commitres;
154- snd_pcm_state_t state;
155- int first = 1;
240 + snd_pcm_sframes_t commitres, frames_read;
241 + int first = 1, first_in = 1;
242 + float frames_in[period_size];
156243
157244 /* main loop: adapted from direct_loop() from alsa-lib/test/pcm.c */
158245 while (1) {
159- state = snd_pcm_state(pcm_out);
160- if (state == SND_PCM_STATE_XRUN) {
161- err = xrun_recovery(pcm_out, -EPIPE);
162- if (err < 0) {
163- printf("XRUN recovery failed: %s\n", snd_strerror(err));
164- return err;
246 + while (pre_begin(pcm_out, &first, period_size));
247 + while (pre_begin(pcm_in, &first_in, period_size));
248 +
249 + frames_read = snd_pcm_mmap_readi(pcm_in, frames_in, period_size);
250 + if (frames_read < 0) {
251 + if ((err = xrun_recovery(pcm_in, err)) < 0) {
252 + warnx("read error: %s", snd_strerror(err));
165253 }
166- first = 1;
167- } else if (state == SND_PCM_STATE_SUSPENDED) {
168- err = xrun_recovery(pcm_out, -ESTRPIPE);
169- if (err < 0) {
170- printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
171- return err;
172- }
254 + first_in = 1;
173255 }
174- avail = snd_pcm_avail_update(pcm_out);
175- if (avail < 0) {
176- err = xrun_recovery(pcm_out, avail);
177- if (err < 0) {
178- printf("avail update failed: %s\n", snd_strerror(err));
179- return err;
180- }
181- first = 1;
182- continue;
183- }
184- if ((snd_pcm_uframes_t)avail < period_size) {
185- if (first) {
186- first = 0;
187- err = snd_pcm_start(pcm_out);
188- if (err < 0) {
189- printf("Start error: %s\n", snd_strerror(err));
190- exit(EXIT_FAILURE);
191- }
192- } else {
193- err = snd_pcm_wait(pcm_out, -1);
194- if (err < 0) {
195- if ((err = xrun_recovery(pcm_out, err)) < 0) {
196- printf("snd_pcm_wait error: %s\n", snd_strerror(err));
197- exit(EXIT_FAILURE);
198- }
199- first = 1;
200- }
201- }
202- continue;
203- }
204- size = period_size;
205- while (size > 0) {
256 +
257 + for (size = period_size; size > 0; size -= frames) {
206258 frames = size;
259 +
207260 err = snd_pcm_mmap_begin(pcm_out, &my_areas, &offset, &frames);
208261 if (err < 0) {
209262 if ((err = xrun_recovery(pcm_out, err)) < 0) {
210- printf("MMAP begin avail error: %s\n", snd_strerror(err));
211- exit(EXIT_FAILURE);
263 + errx(1, "MMAP begin avail error: %s", snd_strerror(err));
212264 }
213265 first = 1;
214266 }
267 + /*
268 + err = snd_pcm_mmap_begin(pcm_in, &my_areas_in, &offset, &frames);
269 + if (err < 0) {
270 + if ((err = xrun_recovery(pcm_in, err)) < 0) {
271 + warnx("read error: %s", snd_strerror(err));
272 + }
273 + first = 1;
274 + }
275 + */
276 +
215277 struct tune *tune = ccdl_get(&ccdl);
216- generate(tune, my_areas, offset, frames, &phase);
278 + generate(tune, my_areas, offset, frames, frames_in, frames_read, &phase);
217279 commitres = snd_pcm_mmap_commit(pcm_out, offset, frames);
218280 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
219281 if ((err = xrun_recovery(pcm_out, commitres >= 0 ? -EPIPE : commitres)) < 0) {
220- printf("MMAP commit error: %s\n", snd_strerror(err));
221- exit(EXIT_FAILURE);
282 + errx(1, "MMAP commit error: %s", snd_strerror(err));
222283 }
223284 first = 1;
224285 }
225- size -= frames;
226286 }
227287
228288 }
229289
tune.cView
@@ -1,10 +1,10 @@
11 #include <math.h>
22 #include "tune.h"
33
4-static float tune_play(struct tune *tune, double time)
4 +static float tune_play(struct tune *tune, double time, float in)
55 {
6- return 0.99 * sin(2. * M_PI * time * 440.);
6 + return 0.99 * (sin(2. * M_PI * time * 440.) * 0.25 + in * 0.75);
77 }
88
99 const struct tune TUNE = {
1010 .play = tune_play,
tune.hView
@@ -1,7 +1,7 @@
11 #pragma once
22
33 struct tune {
4- float (*play)(struct tune *, double time);
4 + float (*play)(struct tune *, double time, float in);
55 };
66
77 extern const struct tune TUNE;

Built with git-ssb-web