1 /*
2     tabaudio.c:
3 
4     Copyright (C) 2018 John ffitch
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24 #include "csoundCore.h"
25 #include "interlocks.h"
26 //#include <pthread.h>
27 #include <sndfile.h>
28 #include "soundio.h"
29 
30 typedef struct {
31     OPDS    h;
32     MYFLT   *kans;
33     MYFLT   *itab;
34     STRINGDAT *file;
35     MYFLT   *format;
36     MYFLT   *beg;
37     MYFLT   *end;
38     /* Local */
39 } TABAUDIO;
40 
41 typedef struct {
42     OPDS    h;
43     MYFLT   *kans;
44     MYFLT   *trig;
45     MYFLT   *itab;
46     STRINGDAT *file;
47     MYFLT   *format;
48     MYFLT   *sync;
49     MYFLT   *beg;
50     MYFLT   *end;
51     /* Local */
52 } TABAUDIOK;
53 
54 typedef struct {
55     CSOUND *csound;
56     MYFLT*   t;
57     uint32_t size;
58     SNDFILE* ff;
59     MYFLT*   ans;
60     void     *thread;
61     OPDS     *h;
62 } SAVE_THREAD;
63 
64 static const int32_t format_table[51] = {
65     /* 0 - 9 */
66     (SF_FORMAT_FLOAT | SF_FORMAT_RAW), (SF_FORMAT_PCM_16 | SF_FORMAT_RAW),
67     SF_FORMAT_PCM_16, SF_FORMAT_ULAW, SF_FORMAT_PCM_16, SF_FORMAT_PCM_32,
68     SF_FORMAT_FLOAT, SF_FORMAT_PCM_U8, SF_FORMAT_PCM_24, SF_FORMAT_DOUBLE,
69     /* 10 - 19 */
70     SF_FORMAT_WAV, (SF_FORMAT_PCM_S8 | SF_FORMAT_WAV),
71     (SF_FORMAT_ALAW | SF_FORMAT_WAV), (SF_FORMAT_ULAW | SF_FORMAT_WAV),
72     (SF_FORMAT_PCM_16 | SF_FORMAT_WAV), (SF_FORMAT_PCM_32 | SF_FORMAT_WAV),
73     (SF_FORMAT_FLOAT | SF_FORMAT_WAV), (SF_FORMAT_PCM_U8 | SF_FORMAT_WAV),
74     (SF_FORMAT_PCM_24 | SF_FORMAT_WAV), (SF_FORMAT_DOUBLE | SF_FORMAT_WAV),
75     /* 20 - 29 */
76     SF_FORMAT_AIFF, (SF_FORMAT_PCM_S8 | SF_FORMAT_AIFF),
77     (SF_FORMAT_ALAW | SF_FORMAT_AIFF), (SF_FORMAT_ULAW | SF_FORMAT_AIFF),
78     (SF_FORMAT_PCM_16 | SF_FORMAT_AIFF), (SF_FORMAT_PCM_32 | SF_FORMAT_AIFF),
79     (SF_FORMAT_FLOAT | SF_FORMAT_AIFF), (SF_FORMAT_PCM_U8 | SF_FORMAT_AIFF),
80     (SF_FORMAT_PCM_24 | SF_FORMAT_AIFF), (SF_FORMAT_DOUBLE | SF_FORMAT_AIFF),
81     /* 30 - 39 */
82     SF_FORMAT_RAW, (SF_FORMAT_PCM_S8 | SF_FORMAT_RAW),
83     (SF_FORMAT_ALAW | SF_FORMAT_RAW), (SF_FORMAT_ULAW | SF_FORMAT_RAW),
84     (SF_FORMAT_PCM_16 | SF_FORMAT_RAW), (SF_FORMAT_PCM_32 | SF_FORMAT_RAW),
85     (SF_FORMAT_FLOAT | SF_FORMAT_RAW), (SF_FORMAT_PCM_U8 | SF_FORMAT_RAW),
86     (SF_FORMAT_PCM_24 | SF_FORMAT_RAW), (SF_FORMAT_DOUBLE | SF_FORMAT_RAW),
87     /* 40 - 49 */
88     SF_FORMAT_IRCAM, (SF_FORMAT_PCM_S8 | SF_FORMAT_IRCAM),
89     (SF_FORMAT_ALAW | SF_FORMAT_IRCAM), (SF_FORMAT_ULAW | SF_FORMAT_IRCAM),
90     (SF_FORMAT_PCM_16 | SF_FORMAT_IRCAM), (SF_FORMAT_PCM_32 | SF_FORMAT_IRCAM),
91     (SF_FORMAT_FLOAT | SF_FORMAT_IRCAM), (SF_FORMAT_PCM_U8 | SF_FORMAT_IRCAM),
92     (SF_FORMAT_PCM_24 | SF_FORMAT_IRCAM), (SF_FORMAT_DOUBLE | SF_FORMAT_IRCAM),
93     /* 50 */
94     (SF_FORMAT_OGG | SF_FORMAT_VORBIS)
95 };
96 
write_tab(void * pp)97 static uintptr_t write_tab(void* pp)
98 {
99     SAVE_THREAD *p = (SAVE_THREAD*)pp;
100     MYFLT*   t = p->t;
101     uint32_t size = p->size;
102     SNDFILE* ff = p->ff;
103     MYFLT*   ans = p->ans;
104     CSOUND*  csound = p->csound;
105     OPDS     *h = p->h;
106     //free(pp);
107     //printf("t=%p size=%d ff=%p\n", t, size, ff);
108     if (sf_writef_MYFLT(ff, t, size) != size) {
109       sf_close(ff);
110       csound->PerfError(csound, h,
111                            Str("tabaudio: failed to write data %d"),size);
112       *ans = -FL(1.0);
113     }
114     else *ans = FL(1.0);
115     sf_close(ff);
116     return 0;
117 }
118 
on_reset_audio(CSOUND * csound,void * pp)119 int on_reset_audio(CSOUND *csound, void *pp)
120 {
121     SAVE_THREAD *p =  (SAVE_THREAD *) pp;
122     csound->JoinThread(p->thread);
123     return 0;
124 }
125 
tabaudiok(CSOUND * csound,TABAUDIOK * p)126 static int32_t tabaudiok(CSOUND *csound, TABAUDIOK *p)
127 {
128     if (*p->trig) {
129       FUNC  *ftp;
130       MYFLT *t;
131       int32_t size, n;
132       SNDFILE *ff;
133       SF_INFO sfinfo;
134       int32_t  format = MYFLT2LRND(*p->format);
135       int32_t  skip = MYFLT2LRND(*p->beg);
136       int32_t  end = MYFLT2LRND(*p->end);
137 
138       if (UNLIKELY((ftp = csound->FTnp2Find(csound, p->itab)) == NULL)) {
139         return csound->PerfError(csound, &(p->h), Str("tabaudio: No table %g"), *p->itab);
140       }
141       *p->kans = FL(0.0);
142       t = ftp->ftable + skip;
143       size = ftp->flenfrms;
144       if (end<=0) size -= skip;
145       else size = end - skip;
146       if (UNLIKELY(size<0 || size>ftp->flenfrms))
147         return csound->PerfError(csound, &(p->h), Str("ftudio: ilegal size"));
148       memset(&sfinfo, 0, sizeof(SF_INFO));
149       if (format >= 51)
150         sfinfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
151       else if (format < 0) {
152         sfinfo.format = FORMAT2SF(csound->oparms->outformat);
153         sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
154       }
155       else sfinfo.format = format_table[format];
156       if (!SF2FORMAT(sfinfo.format))
157         sfinfo.format |= FORMAT2SF(csound->oparms->outformat);
158       if (!SF2TYPE(sfinfo.format))
159         sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
160       sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
161       sfinfo.channels = ftp->nchanls;
162       ff = sf_open(p->file->data, SFM_WRITE, &sfinfo);
163       if (ff==NULL)
164         return csound->PerfError(csound, &(p->h),
165                                  Str("tabaudio: failed to open file %s"),
166                                  p->file->data);
167       if (*p->sync==FL(0.0)) {  /* write in perf thread */
168         if ((n=sf_writef_MYFLT(ff, t, size)) != size) {
169           printf("%s\n", sf_strerror(ff));
170           sf_close(ff);
171           return csound->PerfError(csound, &(p->h),
172                                    Str("tabaudio: failed to write data %d %d"),
173                                    n,size);
174         }
175         sf_close(ff);
176       }
177       else {                    /* Use a helper thread */
178         SAVE_THREAD *q = (SAVE_THREAD*)csound->Malloc(csound, sizeof(SAVE_THREAD));
179         q->t = t;
180         q->size = size;
181         q->ff = ff;
182         q->ans = p->kans;
183         q->csound = csound;
184         q->h = &(p->h);
185         if ((q->thread = csound->CreateThread(write_tab, (void*)q))==NULL) {
186           OPDS * i = q->h;
187           free(q);
188           return csound->PerfError(csound, i,
189                                    Str("Error creating thread"));
190         }
191         csound->RegisterResetCallback(csound, (void*)q, on_reset_audio);
192         /* if (fork() == 0) { */
193         /*   ff = sf_open(p->file->data, SFM_WRITE, &sfinfo); */
194         /*   if (ff==NULL) { */
195         /*     printf(Str("tabaudio: failed to open file %s"), p->file->data); */
196         /*     exit(1); */
197         /*   } */
198         /*   if ((n=sf_writef_MYFLT(ff, t, size)) != size) { */
199         /*     sf_close(ff); */
200         /*     printf("%s %s", Str("tabaudio: failed to write data:"), */
201         /*            sf_strerror(ff)); */
202         /*     exit(1); */
203         /*   } */
204         /*   sf_close(ff); */
205         /*   exit(0); */
206         /* } */
207       }
208       *p->kans = FL(1.0);
209     }
210     else *p->kans = FL(0.0);
211     return OK;
212 }
213 
tabaudioi(CSOUND * csound,TABAUDIO * p)214 static int32_t tabaudioi(CSOUND *csound, TABAUDIO *p)
215 {
216     FUNC  *ftp;
217     MYFLT *t;
218     int32_t size, n;
219     SNDFILE *ff;
220     SF_INFO sfinfo;
221     int32_t  format = MYFLT2LRND(*p->format);
222     int32_t  skip = MYFLT2LRND(*p->beg);
223     int32_t  end = MYFLT2LRND(*p->end);
224 
225     if (UNLIKELY((ftp = csound->FTnp2Find(csound, p->itab)) == NULL)) {
226       return csound->InitError(csound, Str("tabaudio: No table"));
227     }
228     *p->kans = FL(0.0);
229     t = ftp->ftable + skip;
230     size = ftp->flenfrms;
231     if (end<=0) size -= skip;
232     else size = end - skip;
233     if (UNLIKELY(size<0 || size>ftp->flenfrms))
234       return csound->InitError(csound, Str("ftudio: ilegal size"));
235     memset(&sfinfo, 0, sizeof(SF_INFO));
236     if (format >= 51)
237       sfinfo.format = SF_FORMAT_PCM_16 | SF_FORMAT_RAW;
238     else if (format < 0) {
239       sfinfo.format = FORMAT2SF(csound->oparms->outformat);
240       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
241     }
242     else sfinfo.format = format_table[format];
243     if (!SF2FORMAT(sfinfo.format))
244       sfinfo.format |= FORMAT2SF(csound->oparms->outformat);
245     if (!SF2TYPE(sfinfo.format))
246       sfinfo.format |= TYPE2SF(csound->oparms->filetyp);
247     sfinfo.samplerate = (int32_t) MYFLT2LRND(CS_ESR);
248     sfinfo.channels = ftp->nchanls;
249 
250     ff = sf_open(p->file->data, SFM_WRITE, &sfinfo);
251     if (ff==NULL)
252       return csound->InitError(csound, Str("tabaudio: failed to open file %s"),
253                                p->file->data);
254     if ((n=sf_writef_MYFLT(ff, t, size)) != size) {
255       printf("%s\n", sf_strerror(ff));
256       sf_close(ff);
257       return csound->InitError(csound, Str("tabaudio: failed to write data: %s"),
258                                sf_strerror(ff));
259     }
260     *p->kans = FL(1.0);
261     sf_close(ff);
262     return OK;
263 }
264 
265 #define S(x)    sizeof(x)
266 
267 static OENTRY tabaudio_localops[] =
268   {
269    { "ftaudio.i",     S(TABAUDIO),  TR, 1, "i", "iSioo",   (SUBR)tabaudioi, NULL },
270    { "ftaudio.k",     S(TABAUDIOK), TR, 2, "k", "kkSkpOO",  NULL, (SUBR)tabaudiok },
271   };
272 
273 LINKAGE_BUILTIN(tabaudio_localops)
274 
275 
276 
277