A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 251 lines 5.7 kB view raw
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