git ssb

0+

cel / foostudio



Tree: 8c106851aec7aaf152d2963081ee09044b05d1fb

Files: 8c106851aec7aaf152d2963081ee09044b05d1fb / foostudio.c

4140 bytesRaw
1#define _DEFAULT_SOURCE
2#include <alsa/asoundlib.h>
3#include <dlfcn.h>
4#include <err.h>
5#include <math.h>
6#include <stdbool.h>
7#include <stdio.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11#include "tune.h"
12#include "ccdl.h"
13
14#define max(a,b) ((a) > (b) ? (a) : (b))
15#define min(a,b) ((a) < (b) ? (a) : (b))
16
17static unsigned int rate = 48000;
18static unsigned int channels_out = 1;
19static unsigned int channels_in = 1;
20static unsigned int latency = 10000; // us
21static int resample = 1; // allow resampling
22
23static snd_pcm_format_t format = SND_PCM_FORMAT_FLOAT;
24
25int main(int argc, char *argv[])
26{
27 struct ccdl ccdl;
28 int err;
29 snd_pcm_t *pcm_out, *pcm_in;
30 const char *src_fname = "tune.c";
31 const char *device_out = "default";
32 const char *device_in = "default";
33
34 if (argc > 1) src_fname = argv[1];
35 if (argc > 2) device_out = argv[2];
36 if (argc > 3) device_in = argv[3];
37
38 ccdl_init(&ccdl, src_fname, "TUNE");
39
40 if (ccdl_watch(&ccdl)) {
41 errx(1, "ccdl_watch");
42 }
43
44 err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0);
45 if (err < 0) {
46 warnx("Playback open error: %s", snd_strerror(err));
47 return 1;
48 }
49
50 err = snd_pcm_open(&pcm_in, device_in,
51 SND_PCM_STREAM_CAPTURE,
52 SND_PCM_NONBLOCK);
53 if (err < 0) {
54 warnx("Capture open error: %s", snd_strerror(err));
55 return 1;
56 }
57
58 if ((err = snd_pcm_set_params(pcm_out, format,
59 SND_PCM_ACCESS_RW_INTERLEAVED,
60 channels_out, rate, resample, latency)) < 0) {
61 warnx("Playback open error: %s", snd_strerror(err));
62 return 1;
63 }
64
65 if ((err = snd_pcm_set_params(pcm_in, format,
66 SND_PCM_ACCESS_RW_INTERLEAVED,
67 channels_in, rate, resample, latency)) < 0) {
68 warnx("Capture open error: %s", snd_strerror(err));
69 return 1;
70 }
71
72 snd_pcm_uframes_t buffer_size, buffer_size_in, buffer_size_out;
73 snd_pcm_uframes_t period_size, period_size_in, period_size_out;
74 err = snd_pcm_get_params(pcm_in, &buffer_size_in, &period_size_in);
75 if (err < 0) {
76 warnx("Capture get params error: %s", snd_strerror(err));
77 return 1;
78 }
79 err = snd_pcm_get_params(pcm_out, &buffer_size_out, &period_size_out);
80 if (err < 0) {
81 warnx("Playback get params error: %s", snd_strerror(err));
82 return 1;
83 }
84 period_size = min(period_size_in, period_size_out);
85 buffer_size = min(buffer_size_in, buffer_size_out);
86 (void)buffer_size;
87
88 double time = 0;
89 double step = 1/(double)rate;
90 float buffer[period_size];
91
92 if ((err = snd_pcm_prepare(pcm_in) < 0)) {
93 errx(1, "prepare in failed: %s", snd_strerror(err));
94 }
95
96 if ((err = snd_pcm_prepare(pcm_out) < 0)) {
97 errx(1, "prepare out failed: %s", snd_strerror(err));
98 }
99
100 while (1) {
101 snd_pcm_sframes_t frames_in, frames_out;
102
103 frames_in = snd_pcm_readi(pcm_in, buffer, period_size);
104 if (frames_in < 0) {
105 if (frames_in == -EBADFD) {
106 warnx("read in bad state");
107 } else if (frames_in == -EPIPE) {
108 // overrun
109 } else if (frames_in == -ESTRPIPE) {
110 warnx("read while suspended");
111 } else if (frames_in == -EAGAIN) {
112 // not ready
113 } else {
114 warnx("read error: %s", snd_strerror(frames_in));
115 }
116 if ((err = snd_pcm_prepare(pcm_in)) < 0)
117 errx(1, "prepare after read failed: %s\n", snd_strerror(err));
118 continue;
119 }
120
121 struct tune *tune = ccdl_get(&ccdl);
122 if (tune && tune->play) {
123 for (size_t i = 0; i < period_size; i++) {
124 time += step;
125 float frame_in = i < (unsigned)frames_in ? buffer[i] : 0;
126 buffer[i] = tune->play(tune, time, frame_in);
127 }
128 } else {
129 time += step * period_size;
130 }
131
132 frames_out = snd_pcm_writei(pcm_out, buffer, period_size);
133 if (frames_out < 0) {
134 if (frames_out == -EBADFD) {
135 warnx("write in bad state");
136 } else if (frames_out == -EPIPE) {
137 // underrun
138 } else if (frames_out == -ESTRPIPE) {
139 warnx("write while suspended");
140 } else {
141 warnx("write error: %s", snd_strerror(frames_out));
142 }
143 if ((err = snd_pcm_prepare(pcm_out)) < 0)
144 errx(1, "prepare after write failed: %s\n", snd_strerror(err));
145 }
146 }
147
148 snd_pcm_close(pcm_out);
149 snd_pcm_close(pcm_in);
150 return ccdl_deinit(&ccdl);
151}
152

Built with git-ssb-web