git ssb

0+

cel / foostudio



Commit fd156cd03b6fce3c933ce1edb725e8e6e74e7be4

Live reload without delay

cel committed on 10/24/2016, 9:09:53 PM
Parent: 4be6db6a6163e3a0ccd85e7e193f54406c80a29a

Files changed

Makefilechanged
studio.cchanged
tune.cchanged
tune.hchanged
ccdl.cadded
ccdl.hadded
MakefileView
@@ -1,16 +1,8 @@
11 CFLAGS = -std=c99
2-LIB_CFLAGS = -fPIC
3-LDLIBS = -ldl -lasound -lm
4-LIB_LDLIBS = -lm
2 +LDLIBS = -ldl -lasound -lm -lpthread
53
6-all: studio tune.so
4 +studio: studio.o ccdl.o
75
8-studio: studio.c tune.h
9- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
10-
11-tune.so : tune.c tune.h
12- $(CC) $(LIB_CFLAGS) -shared $(LDFLAGS) -o $@ $< $(LIB_LDLIBS)
13-
146 clean:
157 $(RM) *.o *.so studio
168
studio.cView
@@ -8,55 +8,15 @@
88 #include <sys/stat.h>
99 #include <sys/types.h>
1010 #include <unistd.h>
1111 #include "tune.h"
12 +#include "ccdl.h"
1213
13-struct tune_dl {
14- void *handle;
15- ino_t inode;
16- struct tune *tune;
17-};
18-
1914 static unsigned int rate = 44100;
2015 static unsigned int channels = 1;
2116 static unsigned int latency = 500000; /* ring buffer length in us */
2217 static snd_pcm_format_t format = SND_PCM_FORMAT_FLOAT;
23-static const char *dl_fname = "./tune.so";
2418
25-static int tune_dl_load(struct tune_dl *dl, const char *libfname)
26-{
27- struct stat st;
28- if (stat(libfname, &st) < 0) {
29- warn("stat");
30- return -1;
31- }
32- if (dl->inode == st.st_ino) {
33- // file unchanged
34- return 0;
35- }
36- // reload the library
37- if (dl->handle) {
38- dlclose(dl->handle);
39- dl->inode = 0;
40- }
41- dl->handle = dlopen(libfname, RTLD_NOW);
42- if (dl->handle == NULL) {
43- // warnx("dlopen: %s", dlerror());
44- return 0;
45- }
46- dl->tune = dlsym(dl->handle, "TUNE");
47- if (dl->tune == NULL) {
48- warn("dlsym");
49- dlclose(dl->handle);
50- return 0;
51- }
52- dl->inode = st.st_ino;
53- if (dl->tune->reload) {
54- dl->tune->reload(dl->tune);
55- }
56- return 0;
57-}
58-
5919 /*
6020 * Underrun and suspend recovery, from alsa-lib/test/pcm.c
6121 */
6222
@@ -79,9 +39,9 @@
7939 }
8040 return err;
8141 }
8242
83-static void generate(struct tune_dl *dl,
43 +static void generate(struct ccdl *ccdl,
8444 const snd_pcm_channel_area_t *areas,
8545 snd_pcm_uframes_t offset,
8646 int count, double *_phase)
8747 {
@@ -109,19 +69,19 @@
10969 steps[chn] = areas[chn].step / 8;
11070 samples[chn] += offset * steps[chn];
11171 }
11272
113- tune_dl_load(dl, dl_fname);
73 + struct tune *tune = ccdl_get(ccdl);
11474
11575 /* fill the channel areas */
11676 while (count-- > 0) {
11777 union {
11878 float f;
11979 int i;
12080 } fval;
12181 int res, i;
122- if (dl->handle && dl->tune->play) {
123- fval.f = dl->tune->play(dl->tune, phase);
82 + if (tune && tune->play) {
83 + fval.f = tune->play(tune, phase);
12484 } else {
12585 fval.f = 0;
12686 }
12787 res = fval.i;
@@ -149,19 +109,21 @@
149109
150110
151111 int main(int argc, char *argv[])
152112 {
153- struct tune_dl dl = {0};
113 + struct ccdl ccdl;
154114 int err;
155115 snd_pcm_t *pcm_out;
116 + const char *src_fname = "tune.c";
156117 const char *device_out = "default";
157118
158- if (argc > 2) {
159- device_out = argv[2];
160- }
119 + if (argc > 1) src_fname = argv[1];
120 + if (argc > 2) device_out = argv[2];
161121
162- if (tune_dl_load(&dl, dl_fname) < 0) {
163- return 1;
122 + ccdl_init(&ccdl, src_fname, "TUNE");
123 +
124 + if (ccdl_watch(&ccdl)) {
125 + errx(1, "ccdl_watch");
164126 }
165127
166128 if ((err = snd_pcm_open(&pcm_out, device_out, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
167129 warnx("Playback open error: %s", snd_strerror(err));
@@ -178,12 +140,8 @@
178140 warnx("Playback open error: %s", snd_strerror(err));
179141 return 1;
180142 }
181143
182- if (dl.tune->init) {
183- dl.tune->init(dl.tune);
184- }
185-
186144 snd_pcm_uframes_t buffer_size;
187145 snd_pcm_uframes_t period_size;
188146 if ((err = snd_pcm_get_params(pcm_out, &buffer_size, &period_size)) < 0) {
189147 warnx("Playback get params error: %s", snd_strerror(err));
@@ -253,9 +211,9 @@
253211 exit(EXIT_FAILURE);
254212 }
255213 first = 1;
256214 }
257- generate(&dl, my_areas, offset, frames, &phase);
215 + generate(&ccdl, my_areas, offset, frames, &phase);
258216 // generate_sine(my_areas, offset, frames, &phase);
259217 commitres = snd_pcm_mmap_commit(pcm_out, offset, frames);
260218 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
261219 if ((err = xrun_recovery(pcm_out, commitres >= 0 ? -EPIPE : commitres)) < 0) {
@@ -267,10 +225,8 @@
267225 size -= frames;
268226 }
269227
270228 }
271- if (dl.tune->deinit) {
272- dl.tune->deinit(dl.tune);
273- }
274229
275230 snd_pcm_close(pcm_out);
231 + return ccdl_deinit(&ccdl);
276232 }
tune.cView
@@ -1,26 +1,11 @@
11 #include <math.h>
22 #include "tune.h"
33
4-static void tune_init(struct tune *tune)
5-{
6-}
7-
8-static void tune_reload(struct tune *tune)
9-{
10-}
11-
124 static float tune_play(struct tune *tune, double time)
135 {
146 return 0.99 * sin(time*440);
157 }
168
17-static void tune_deinit(struct tune *tune)
18-{
19-}
20-
219 const struct tune TUNE = {
22- .init = tune_init,
23- .reload = tune_reload,
2410 .play = tune_play,
25- .deinit = tune_deinit,
2611 };
tune.hView
@@ -1,10 +1,7 @@
11 #pragma once
22
33 struct tune {
4- void (*init)(struct tune *);
5- void (*deinit)(struct tune *);
6- void (*reload)(struct tune *);
74 float (*play)(struct tune *, double time);
85 };
96
107 extern const struct tune TUNE;
ccdl.cView
@@ -1,0 +1,197 @@
1 +#include <stddef.h>
2 +#include <unistd.h>
3 +#include <stdio.h>
4 +#include <stdlib.h>
5 +#include <err.h>
6 +#include <sys/wait.h>
7 +#include <sys/inotify.h>
8 +#include <dlfcn.h>
9 +#include <pthread.h>
10 +
11 +#include "ccdl.h"
12 +
13 +static unsigned int tmp_i = 0;
14 +
15 +static const char *mktemp()
16 +{
17 + const char *tmpdir = getenv("TMPDIR");
18 + if (!tmpdir) tmpdir = "/tmp";
19 + static char buf[256];
20 + if (snprintf(buf, sizeof(buf), "%s/ccdl-%d-%i.so",
21 + tmpdir, getpid(), tmp_i++) < 0) return NULL;
22 + return buf;
23 +}
24 +
25 +void lib_init(struct lib *lib, const char *src_fname, const char *sym_name)
26 +{
27 + lib->src_fname = src_fname;
28 + lib->lib_fname = NULL;
29 + lib->sym_name = sym_name;
30 + lib->handle = NULL;
31 + lib->sym = NULL;
32 +}
33 +
34 +static int compile(const char *src, const char *lib)
35 +{
36 + if (!src || !lib) return -1;
37 + int child = fork();
38 + if (child < 0) return -1;
39 + if (child == 0) {
40 + char *const argv[] = {
41 + "cc", (char *)src, "-o", (char *)lib,
42 + "-fPIC", "-shared", "-lm", "-std=c99",
43 + NULL};
44 + return execvp(argv[0], argv);
45 + } else {
46 + int wstatus;
47 + if (waitpid(child, &wstatus, 0) < 0) {
48 + return -1;
49 + } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) {
50 + return 0;
51 + } else {
52 + return -1;
53 + }
54 + }
55 +}
56 +
57 +int lib_build(struct lib *lib)
58 +{
59 + void *handle = lib->handle;
60 + if (!handle) {
61 + const char *lib_fname = lib->lib_fname;
62 + if (!lib_fname) {
63 + const char *src_fname = lib->src_fname;
64 + if (!src_fname) return -1;
65 + lib_fname = mktemp();
66 + if (!lib_fname) return -1;
67 + lib->lib_fname = lib_fname;
68 + if (compile(src_fname, lib_fname)) return -1;
69 + }
70 + handle = dlopen(lib_fname, RTLD_NOW);
71 + lib->handle = handle;
72 + }
73 + const char *sym_name = lib->sym_name;
74 + if (!sym_name) return -1;
75 + void *sym = dlsym(handle, sym_name);
76 + if (!sym) return -1;
77 + lib->sym = sym;
78 + return 0;
79 +}
80 +
81 +void *lib_get(struct lib *lib)
82 +{
83 + if (!lib->sym) lib_build(lib);
84 + return lib->sym;
85 +}
86 +
87 +void lib_deinit(struct lib *lib)
88 +{
89 + if (lib->handle) {
90 + dlclose(lib->handle);
91 + lib->handle = NULL;
92 + lib->sym = NULL;
93 + }
94 + if (lib->lib_fname) {
95 + unlink(lib->lib_fname);
96 + lib->lib_fname = NULL;
97 + }
98 +}
99 +
100 +void ccdl_init(struct ccdl *ccdl, const char *src_fname, const char *sym_name)
101 +{
102 + lib_init(&ccdl->libs[0], src_fname, sym_name);
103 + lib_init(&ccdl->libs[1], src_fname, sym_name);
104 + ccdl->lib = &ccdl->libs[0];
105 +}
106 +
107 +static struct lib *ccdl_get_old_lib(struct ccdl *ccdl)
108 +{
109 + return ccdl->lib == &ccdl->libs[1] ? &ccdl->libs[0] : &ccdl->libs[1];
110 +}
111 +
112 +void *ccdl_get(struct ccdl *ccdl)
113 +{
114 + struct lib *old_lib = ccdl_get_old_lib(ccdl);
115 + if (old_lib) {
116 + lib_deinit(old_lib);
117 + }
118 + return lib_get(ccdl->lib);
119 +}
120 +
121 +static int ccdl_watch_run(struct ccdl *ccdl)
122 +{
123 + int ifd = inotify_init();
124 + if (ifd < 0) {
125 + warn("inotify_init");
126 + return -1;
127 + }
128 + if (!ccdl || !ccdl->lib || !ccdl->lib->src_fname) {
129 + warn("missing lib filename");
130 + return -1;
131 + }
132 + if (inotify_add_watch(ifd, ccdl->lib->src_fname, IN_MODIFY) < 0) {
133 + warn("watch");
134 + return -1;
135 + }
136 +
137 + while (1) {
138 + struct inotify_event ev;
139 + ssize_t len = read(ifd, &ev, sizeof ev);
140 + //printf("readed %zd %u %u %u\n", len, sizeof ev, ev.len, ev.mask);
141 + if (len < 0) {
142 + warn("read");
143 + return -1;
144 + }
145 + if (len < sizeof ev) {
146 + warn("small read");
147 + continue;
148 + }
149 + if (ev.len > 0) {
150 + warn("unexpected name");
151 + return -1;
152 + }
153 + if (!(ev.mask & IN_MODIFY)) {
154 + printf("unknown mask: %u\n", ev.mask);
155 + continue;
156 + }
157 +
158 + (void)ccdl_rebuild(ccdl);
159 + }
160 +
161 + return 0;
162 +}
163 +
164 +static void *ccdl_watch_run_thread(void *ccdl)
165 +{
166 + return (void *)ccdl_watch_run(ccdl);
167 +}
168 +
169 +int ccdl_watch(struct ccdl *ccdl)
170 +{
171 + pthread_t *id = &ccdl->watcher_thread;
172 + if (pthread_create(id, NULL, ccdl_watch_run_thread, ccdl)) return -1;
173 + return 0;
174 +}
175 +
176 +int ccdl_rebuild(struct ccdl *ccdl)
177 +{
178 + struct lib *old_lib, *new_lib;
179 + old_lib = ccdl->lib;
180 + new_lib = ccdl_get_old_lib(ccdl);
181 + lib_deinit(new_lib);
182 + if (lib_build(new_lib) < 0) return -1;
183 + ccdl->lib = new_lib;
184 + return 0;
185 +}
186 +
187 +int ccdl_deinit(struct ccdl *ccdl)
188 +{
189 + pthread_t thread = ccdl->watcher_thread;
190 + if (thread) {
191 + void *retval;
192 + pthread_join(thread, &retval);
193 + return (int)retval;
194 + }
195 + return 0;
196 +}
197 +
ccdl.hView
@@ -1,0 +1,27 @@
1 +#pragma once
2 +
3 +#include <pthread.h>
4 +
5 +struct lib {
6 + const char *src_fname;
7 + const char *lib_fname;
8 + const char *sym_name;
9 + void *handle;
10 + void *sym;
11 +};
12 +
13 +struct ccdl {
14 + struct lib libs[2], *lib;
15 + pthread_t watcher_thread;
16 +};
17 +
18 +void lib_init(struct lib *, const char *src_fname, const char *sym_name);
19 +int lib_build(struct lib *);
20 +void *lib_get(struct lib *);
21 +void lib_deinit(struct lib *);
22 +
23 +void ccdl_init(struct ccdl *, const char *src_fname, const char *sym_name);
24 +void *ccdl_get(struct ccdl *);
25 +int ccdl_watch(struct ccdl *);
26 +int ccdl_rebuild(struct ccdl *);
27 +int ccdl_deinit(struct ccdl *);

Built with git-ssb-web