Files: 8c106851aec7aaf152d2963081ee09044b05d1fb / foostudio.c
4140 bytesRaw
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | static unsigned int rate = 48000; |
18 | static unsigned int channels_out = 1; |
19 | static unsigned int channels_in = 1; |
20 | static unsigned int latency = 10000; // us |
21 | static int resample = 1; // allow resampling |
22 | |
23 | static snd_pcm_format_t format = SND_PCM_FORMAT_FLOAT; |
24 | |
25 | int 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