A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1#ifdef ROCKBOX
2#include "plugin.h"
3#include "../../pdbox.h"
4#else /* ROCKBOX */
5#include <unistd.h>
6#include <fcntl.h>
7#include <errno.h>
8#include <stdio.h>
9#include <string.h>
10#include <unistd.h>
11#include <sys/mman.h>
12#include <sys/stat.h>
13#endif /* ROCKBOX */
14
15#include "../src/m_pd.h"
16#include "../src/m_fixed.h"
17#include "../src/g_canvas.h"
18
19
20#define BLOCKTIME 10
21
22#define MAX_CHANS 4
23
24#include "sformat.h"
25
26static t_class *sfwrite_class;
27
28typedef struct _sfwrite
29{
30 t_object x_obj;
31 t_symbol* filename;
32 int x_file;
33
34 t_int rec;
35 t_int x_channels;
36 uint32 size;
37 t_glist * x_glist;
38 t_int x_blocked;
39 t_int x_blockwarn;
40} t_sfwrite;
41
42
43static void sfwrite_wave_setup(t_sfwrite* x,t_wave* w)
44{
45
46 strncpy(w->w_fileid,"RIFF",4); /* chunk id 'RIFF' */
47 w->w_chunksize = x->size + sizeof(t_wave) -8; /* chunk size */
48 strncpy(w->w_waveid,"WAVE",4); /* wave chunk id 'WAVE' */
49 strncpy(w->w_fmtid,"fmt ",4); /* format chunk id 'fmt '*/
50 w->w_fmtchunksize = 16; /* format chunk size */
51 w->w_fmttag = 1; /* format tag, 1 for PCM */
52 w->w_nchannels = x->x_channels; /* number of channels */
53 w->w_samplespersec = 44100; /* sample rate in hz */
54 w->w_navgbytespersec = 44100*x->x_channels*2; /* average bytes per second */
55 w->w_nblockalign = 4; /* number of bytes per sample */
56 w->w_nbitspersample = 16; /* number of bits in a sample */
57 strncpy(w->w_datachunkid,"data",4); /* data chunk id 'data'*/
58 w->w_datachunksize = x->size; /* length of data chunk */
59}
60
61
62
63static void sfwrite_close(t_sfwrite *x)
64{
65 if (x->x_file > 0) {
66 t_wave w;
67 sfwrite_wave_setup(x,&w);
68 lseek(x->x_file,0,SEEK_SET);
69 write(x->x_file,&w,sizeof(w));
70 close(x->x_file);
71 }
72 x->x_file = -1;
73}
74
75
76static void sfwrite_open(t_sfwrite *x,t_symbol *filename)
77{
78 char fname[MAXPDSTRING];
79
80 if (filename == &s_) {
81 post("sfwrite: open without filename");
82 return;
83 }
84
85 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
86 fname, MAXPDSTRING);
87
88 x->x_blocked = 0;
89 x->filename = filename;
90 post("sfwrite: filename = %s",x->filename->s_name);
91
92 sfwrite_close(x);
93
94 if ((x->x_file = open(fname,O_RDWR | O_CREAT,0664)) < 0)
95 {
96 error("can't create %s",fname);
97 return;
98 }
99
100 /* skip the header */
101
102 lseek(x->x_file,sizeof(t_wave),SEEK_SET);
103 x->size = 0;
104
105
106}
107
108static void sfwrite_block(t_sfwrite *x, t_floatarg f)
109{
110 x->x_blockwarn = f;
111}
112
113
114static void sfwrite_float(t_sfwrite *x, t_floatarg f)
115{
116 int t = f;
117 if (t) {
118 post("sfwrite: start", f);
119 x->rec=1;
120 }
121 else {
122 post("sfwrite: stop", f);
123 x->rec=0;
124 }
125
126}
127
128
129static short out[4*64];
130
131static t_int *sfwrite_perform(t_int *w)
132{
133 t_sfwrite* x = (t_sfwrite*)(w[1]);
134 t_sample * in[4];
135 int c = x->x_channels;
136 int i,num,n;
137 short* tout = out;
138 int ret;
139#ifndef ROCKBOX
140 int timebefore,timeafter;
141 double late;
142#endif
143
144 for (i=0;i < c;i++) {
145 in[i] = (t_sample *)(w[2+i]);
146 }
147
148 n = num = (int)(w[2+c]);
149
150 /* loop */
151
152 if (x->rec && x->x_file) {
153
154 while (n--) {
155 for (i=0;i<c;i++) {
156 *tout++ = (*(in[i])++)>>(fix1-16);
157 }
158 }
159
160#ifndef ROCKBOX
161 timebefore = sys_getrealtime();
162#endif
163 if ((ret =write(x->x_file,out,sizeof(short)*num*c)) < (signed int)sizeof(short)*num*c) {
164 post("sfwrite: short write %d",ret);
165
166 }
167#ifndef ROCKBOX
168 timeafter = sys_getrealtime();
169 late = timeafter - timebefore;
170#endif
171
172#if 0
173 /* OK, we let only 10 ms block here */
174 if (late > BLOCKTIME && x->x_blockwarn) {
175 post("sfwrite blocked %f ms",late*1000);
176 x->x_blocked++;
177 if (x->x_blocked > x->x_blockwarn) {
178 x->rec = 0;
179 post("maximum blockcount %d reached, recording stopped (set blockcount with \"block <num>\"",x->x_blockwarn);
180 }
181 }
182#endif
183 x->size +=64*x->x_channels*sizeof(short) ;
184 }
185
186 return (w+3+c);
187}
188
189
190
191static void sfwrite_dsp(t_sfwrite *x, t_signal **sp)
192{
193 switch (x->x_channels) {
194 case 1:
195 dsp_add(sfwrite_perform, 3, x, sp[0]->s_vec,
196 sp[0]->s_n);
197 break;
198 case 2:
199 dsp_add(sfwrite_perform, 4, x, sp[0]->s_vec,
200 sp[1]->s_vec, sp[0]->s_n);
201 break;
202 case 4:
203 dsp_add(sfwrite_perform, 6, x, sp[0]->s_vec,
204 sp[1]->s_vec,
205 sp[2]->s_vec,
206 sp[3]->s_vec,
207 sp[0]->s_n);
208 break;
209 }
210}
211
212static void sfwrite_free(t_sfwrite* x)
213{
214 sfwrite_close(x);
215}
216
217
218static void *sfwrite_new(t_floatarg chan)
219{
220 t_sfwrite *x = (t_sfwrite *)pd_new(sfwrite_class);
221 t_int c = chan;
222
223 if (c<1 || c > MAX_CHANS) c = 1;
224
225 x->x_glist = (t_glist*) canvas_getcurrent();
226 x->x_channels = c--;
227 x->x_file=0;
228 x->rec = 0;
229 x->size = 0;
230 x->x_blocked = 0;
231 x->x_blockwarn = 10;
232 while (c--) {
233 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
234 }
235
236
237 return (x);
238}
239
240void sfwrite_tilde_setup(void)
241{
242 sfwrite_class = class_new(gensym("sfwrite~"), (t_newmethod)sfwrite_new, (t_method)sfwrite_free,
243 sizeof(t_sfwrite), 0,A_DEFFLOAT,0);
244 class_addmethod(sfwrite_class,nullfn,gensym("signal"), 0);
245 class_addmethod(sfwrite_class, (t_method) sfwrite_dsp, gensym("dsp"), 0);
246 class_addmethod(sfwrite_class, (t_method) sfwrite_open, gensym("open"), A_SYMBOL,A_NULL);
247 class_addmethod(sfwrite_class, (t_method) sfwrite_close, gensym("close"), 0);
248 class_addmethod(sfwrite_class, (t_method)sfwrite_block,gensym("block"),A_DEFFLOAT,0);
249 class_addfloat(sfwrite_class, sfwrite_float);
250}
251