git ssb

0+

cel / foostudio



Tree: 033d2aa1890af2ff80fde819e83b034484c47cbc

Files: 033d2aa1890af2ff80fde819e83b034484c47cbc / foostudio.c

5298 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
22static int16_t maxval = 0x7fff;
23
24static snd_pcm_format_t format = SND_PCM_FORMAT_S16;
25
26int main(int argc, char *argv[])
27{
28 struct ccdl ccdl;
29 void *tune_obj = NULL;
30 int err;
31 snd_pcm_t *pcm_out = NULL, *pcm_in = NULL;
32 snd_rawmidi_t *midi_in = NULL;
33 const char *src_fname = "tune.c";
34 const char *device_out = "default";
35 const char *device_in = "default";
36 const char *midi_device_in = "default";
37
38 if (argc > 1) src_fname = argv[1];
39 if (argc > 2) device_out = argv[2];
40 if (argc > 3) device_in = argv[3];
41 if (argc > 4) midi_device_in = argv[4];
42
43 if (device_in[0] == '\0') device_in = NULL;
44 if (midi_device_in[0] == '\0') midi_device_in = NULL;
45
46 ccdl_init(&ccdl, src_fname, "play");
47
48 if (ccdl_watch(&ccdl)) {
49 errx(1, "ccdl_watch");
50 }
51
52 err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0);
53 if (err < 0) {
54 warnx("Playback open error: %s", snd_strerror(err));
55 return 1;
56 }
57
58 if (device_in) {
59 err = snd_pcm_open(&pcm_in, device_in,
60 SND_PCM_STREAM_CAPTURE,
61 SND_PCM_NONBLOCK);
62 if (err < 0) {
63 warnx("Capture open error: %s", snd_strerror(err));
64 return 1;
65 }
66 }
67
68 if (midi_device_in) {
69 err = snd_rawmidi_open(&midi_in, NULL, midi_device_in,
70 SND_RAWMIDI_NONBLOCK);
71 if (err < 0) {
72 warnx("Midi open error: %s", snd_strerror(err));
73 }
74 }
75
76 if ((err = snd_pcm_set_params(pcm_out, format,
77 SND_PCM_ACCESS_RW_INTERLEAVED,
78 channels_out, rate, resample, latency)) < 0) {
79 warnx("Playback params error: %s", snd_strerror(err));
80 return 1;
81 }
82
83 if (pcm_in) {
84 if ((err = snd_pcm_set_params(pcm_in, format,
85 SND_PCM_ACCESS_RW_INTERLEAVED,
86 channels_in, rate, resample, latency)) < 0) {
87 warnx("Capture params error: %s", snd_strerror(err));
88 return 1;
89 }
90 }
91
92 snd_pcm_uframes_t buffer_size, buffer_size_in;
93 snd_pcm_uframes_t period_size, period_size_in;
94
95 err = snd_pcm_get_params(pcm_out, &buffer_size, &period_size);
96 if (err < 0) {
97 warnx("Playback get params error: %s", snd_strerror(err));
98 return 1;
99 }
100 if (pcm_in) {
101 err = snd_pcm_get_params(pcm_in, &buffer_size_in, &period_size_in);
102 if (err < 0) {
103 warnx("Capture get params error: %s", snd_strerror(err));
104 return 1;
105 }
106 period_size = min(period_size_in, period_size);
107 buffer_size = min(buffer_size_in, buffer_size);
108 }
109 (void)buffer_size;
110 // printf("a %zu\n", (size_t)period_size);
111
112 double time = 0;
113 double step = 1/(double)rate;
114 int midi_reopen_timer = 0;
115
116 while (1) {
117 snd_pcm_sframes_t frames, frames_in = 0, frames_out;
118 // frames = snd_pcm_avail_update(pcm_out);
119 frames = period_size;
120 if (frames < 0) {
121 err = snd_pcm_recover(pcm_out, frames, 0);
122 if (err) err = snd_pcm_wait(pcm_out, 1000);
123 if (err) warnx("snd_pcm_wait(%s)", snd_strerror(err));
124 continue;
125 }
126 int16_t buffer[frames];
127
128 if (pcm_in) {
129 if (snd_pcm_state(pcm_in) == SND_PCM_STATE_PREPARED) {
130 if ((err = snd_pcm_start(pcm_in)) < 0) {
131 warnx("snd_pcm_start: %s", snd_strerror(err));
132 }
133 }
134 frames_in = snd_pcm_readi(pcm_in, buffer, frames);
135 if (frames_in < 0) {
136 err = snd_pcm_recover(pcm_in, frames_in, 0);
137 if (err == -EAGAIN) {
138 } else if (err < 0) {
139 warnx("snd_pcm_readi: %s\n", snd_strerror(err));
140 }
141 }
142 }
143
144 if (midi_reopen_timer > 0) {
145 if (--midi_reopen_timer == 0) {
146 err = snd_rawmidi_open(&midi_in, NULL, midi_device_in,
147 SND_RAWMIDI_NONBLOCK);
148 if (err < 0) {
149 warnx("midi device re-open failed: %s", snd_strerror(err));
150 midi_reopen_timer = 5;
151 }
152 }
153 }
154
155 unsigned char midi_buf[frames], *midi_bufp = NULL;
156 size_t midi_bytes = 0;
157 if (midi_in) {
158 ssize_t bytes = snd_rawmidi_read(midi_in, midi_buf, frames);
159 if (bytes > 0) {
160 midi_bufp = midi_buf;
161 midi_bytes = bytes;
162 } else if (bytes == -EAGAIN) {
163 } else if (bytes == -ENODEV) {
164 // lost device. queue reopening it
165 midi_in = NULL;
166 midi_reopen_timer = 5;
167 } else if (bytes < 0) {
168 warnx("snd_rawmidi_read: %s (%zd)", snd_strerror(bytes), bytes);
169 }
170 }
171
172 play_fn *play;
173 *(void **)(&play) = ccdl_get(&ccdl);
174 if (play) {
175 for (size_t i = 0; i < (size_t)frames; i++) {
176 time += step;
177 int16_t frame_in = (ssize_t)i < frames_in ? buffer[i] : 0;
178 float in = (float)frame_in / maxval;
179 float val = play(&tune_obj, time, in, midi_bufp);
180 if (midi_bufp) {
181 if (midi_bytes <= 3) {
182 midi_bufp = NULL;
183 } else {
184 midi_bufp += 3;
185 midi_bytes -= 3;
186 }
187 }
188 buffer[i] = val * maxval;
189 }
190 } else {
191 time += step * frames;
192 }
193
194 frames_out = snd_pcm_writei(pcm_out, buffer, frames);
195 if (frames_out < 0) snd_pcm_recover(pcm_out, frames_out, 0);
196 }
197
198 snd_rawmidi_close(midi_in);
199 snd_pcm_close(pcm_out);
200 snd_pcm_close(pcm_in);
201 return ccdl_deinit(&ccdl);
202}
203

Built with git-ssb-web