Updating built in Io code to use += instead of x = x + y
[io/quag.git] / addons / LibSndFile / source / IoLibSndFile.c
blobe740cfa47e4753780384752e4b173a7e805b248a
1 /*#io
2 LibSndFile ioDoc(
3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
5 docCategory("Media")
6 docDescription("""An object for encoding and decoding audio and video streams.""")
7 */
9 #include "IoLibSndFile.h"
10 #include "List.h"
11 #include "IoState.h"
12 #include "IoNumber.h"
13 #include "IoSeq.h"
14 #include "IoList.h"
15 #include <limits.h>
17 #define DATA(self) ((IoLibSndFileData *)IoObject_dataPointer(self))
19 IoTag *IoLibSndFile_newTag(void *state)
21 IoTag *tag = IoTag_newWithName_("LibSndFile");
22 IoTag_state_(tag, state);
23 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoLibSndFile_rawClone);
24 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoLibSndFile_mark);
25 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoLibSndFile_free);
26 return tag;
29 IoLibSndFile *IoLibSndFile_proto(void *state)
31 IoObject *self = IoObject_new(state);
32 IoObject_tag_(self, IoLibSndFile_newTag(state));
34 IoObject_setDataPointer_(self, calloc(1, sizeof(IoLibSndFileData)));
36 DATA(self)->outputBuffer = IoSeq_new(state);
37 DATA(self)->sfinfo = calloc(1, sizeof(SF_INFO));
39 IoState_registerProtoWithFunc_(state, self, IoLibSndFile_proto);
42 IoMethodTable methodTable[] = {
43 {"outputBuffer", IoLibSndFile_outputBuffer},
44 {"formatNames", IoLibSndFile_formatNames},
45 {"openForReading", IoLibSndFile_openForReading},
46 {"openForWriting", IoLibSndFile_openForWriting},
47 {"read", IoLibSndFile_read},
48 {"write", IoLibSndFile_write},
49 {"close", IoLibSndFile_close},
50 {NULL, NULL},
52 IoObject_addMethodTable_(self, methodTable);
54 return self;
57 IoLibSndFile *IoLibSndFile_rawClone(IoLibSndFile *proto)
59 IoObject *self = IoObject_rawClonePrimitive(proto);
60 IoObject_setDataPointer_(self, calloc(1, sizeof(IoLibSndFileData)));
62 DATA(self)->outputBuffer = IOCLONE(DATA(proto)->outputBuffer);
63 DATA(self)->sfinfo = calloc(1, sizeof(SF_INFO));
65 return self;
68 IoLibSndFile *IoLibSndFile_new(void *state)
70 IoObject *proto = IoState_protoWithInitFunction_(state, IoLibSndFile_proto);
71 return IOCLONE(proto);
74 // -----------------------------------------------------------
76 void IoLibSndFile_free(IoLibSndFile *self)
78 free(DATA(self)->sfinfo);
79 free(IoObject_dataPointer(self));
82 void IoLibSndFile_mark(IoLibSndFile *self)
84 IoObject_shouldMark(DATA(self)->outputBuffer);
87 // -----------------------------------------------------------
89 IoObject *IoLibSndFile_outputBuffer(IoLibSndFile *self, IoObject *locals, IoMessage *m)
91 /*#io
92 docSlot("outputBuffer", "Returns the output buffer.")
94 return DATA(self)->outputBuffer;
97 IoObject *IoLibSndFile_stop(IoLibSndFile *self, IoObject *locals, IoMessage *m)
99 /*#io
100 docSlot("stop", "Stops processing data.")
102 DATA(self)->isRunning = 0;
103 return self;
106 IoObject *IoLibSndFile_isRunning(IoLibSndFile *self, IoObject *locals, IoMessage *m)
108 /*#io
109 docSlot("isRunning", "Returns true if it's running, false otherwise.")
111 return IOBOOL(self, DATA(self)->isRunning);
114 IoObject *IoLibSndFile_formatNames(IoLibSndFile *self, IoObject *locals, IoMessage *m)
116 /*#io
117 docSlot("formatNames", "Returns a list of strings with the names of the supported codecs.")
119 IoList *names = IoList_new(IOSTATE);
122 SF_FORMAT_INFO format_info;
123 int k, count;
125 sf_command(DATA(self)->sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof(int));
127 for (k = 0 ; k < count ; k++)
129 format_info.format = k ;
130 sf_command (sndfile, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof(format_info));
131 printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension);
132 IoList_rawAppend_(names, IOSYMBOL(format_info.name));
136 return names;
139 int IoLibSndFile_IdOfFormat(char *f)
141 char *r = strrchr(f, '.');
142 // add code to deal with case
144 if (r)
146 f = r + 1;
149 if (!strcmp(f, "wav")) return SF_FORMAT_WAV | SF_FORMAT_FLOAT;
150 if (!strcmp(f, "aiff")) return SF_FORMAT_AIFF;
151 if (!strcmp(f, "au")) return SF_FORMAT_AU;
152 if (!strcmp(f, "raw")) return SF_FORMAT_RAW;
153 if (!strcmp(f, "paf")) return SF_FORMAT_PAF;
154 if (!strcmp(f, "svx")) return SF_FORMAT_SVX;
155 if (!strcmp(f, "nist")) return SF_FORMAT_NIST;
156 if (!strcmp(f, "voc")) return SF_FORMAT_VOC;
157 if (!strcmp(f, "ircam")) return SF_FORMAT_IRCAM;
158 if (!strcmp(f, "w64")) return SF_FORMAT_W64;
159 if (!strcmp(f, "mat4")) return SF_FORMAT_MAT4;
160 if (!strcmp(f, "mat5")) return SF_FORMAT_MAT5;
162 return 0;
166 // -----------------------------------------------------------
168 IoObject *IoLibSndFile_openForReading(IoLibSndFile *self, IoObject *locals, IoMessage *m)
170 if (!DATA(self)->sndfile)
172 IoSeq *path = IoObject_symbolGetSlot_(self, IOSYMBOL("path"));
173 IOASSERT(path, "missing path slot");
174 DATA(self)->sndfile = sf_open(CSTRING(path), SFM_READ, DATA(self)->sfinfo);
175 IOASSERT(DATA(self)->sndfile, sf_strerror(NULL));
178 IoObject_setSlot_to_(self, IOSYMBOL("frames"), IONUMBER(DATA(self)->sfinfo->frames));
179 IoObject_setSlot_to_(self, IOSYMBOL("sampleRate"), IONUMBER(DATA(self)->sfinfo->samplerate));
180 IoObject_setSlot_to_(self, IOSYMBOL("channels"), IONUMBER(DATA(self)->sfinfo->channels));
181 IoObject_setSlot_to_(self, IOSYMBOL("format"), IONUMBER(DATA(self)->sfinfo->format));
182 IoObject_setSlot_to_(self, IOSYMBOL("seekable"), IONUMBER(DATA(self)->sfinfo->seekable));
183 //IoObject_setSlot_to_(self, IOSYMBOL("size"), IONUMBER(DATA(self)->sfinfo->size));
184 return self;
187 IoObject *IoLibSndFile_openForWriting(IoLibSndFile *self, IoObject *locals, IoMessage *m)
189 if (!DATA(self)->sndfile)
191 IoSeq *path = IoObject_symbolGetSlot_(self, IOSYMBOL("path"));
192 IOASSERT(path, "missing path slot");
194 //DATA(self)->sfinfo->frames = (sf_count_t)IoObject_doubleGetSlot_(self, IOSYMBOL("frames"));
195 DATA(self)->sfinfo->samplerate = (sf_count_t)IoObject_doubleGetSlot_(self, IOSYMBOL("sampleRate"));
196 DATA(self)->sfinfo->channels = (sf_count_t)IoObject_doubleGetSlot_(self, IOSYMBOL("channels"));
197 DATA(self)->sfinfo->format = IoLibSndFile_IdOfFormat(CSTRING(path));
199 DATA(self)->sndfile = sf_open(CSTRING(path), SFM_READ, DATA(self)->sfinfo);
200 IOASSERT(DATA(self)->sndfile, sf_strerror(NULL));
203 return self;
206 IoObject *IoLibSndFile_close(IoLibSndFile *self, IoObject *locals, IoMessage *m)
208 if (DATA(self)->sndfile)
210 sf_close(DATA(self)->sndfile);
213 return self;
216 IoObject *IoLibSndFile_read(IoLibSndFile *self, IoObject *locals, IoMessage *m)
218 /*#io
219 docSlot("read(numberOfFrames)", "Read a given number of frames (sample pairs).")
222 sf_count_t framesToRead = IoMessage_locals_intArgAt_(m, locals, 0);
223 sf_count_t samplesRead = 0;
225 IoLibSndFile_openForReading(self, locals, m);
227 if (framesToRead)
229 UArray *outba = IoSeq_rawUArray(DATA(self)->outputBuffer);
230 size_t samplesToRead = framesToRead * DATA(self)->sfinfo->channels;
231 size_t bytesToRead = samplesToRead * sizeof(float);
233 size_t oldSize = UArray_size(outba);
234 float *buf;
235 UArray_setSize_(outba, oldSize + bytesToRead);
236 buf = (float *)(UArray_bytes(outba) + oldSize);
238 samplesRead = sf_read_float(DATA(self)->sndfile, buf, samplesToRead);
240 UArray_setSize_(outba, oldSize + (samplesRead * sizeof(float)));
242 if (samplesRead != samplesToRead) return IONIL(self);
246 return self;
249 IoObject *IoLibSndFile_write(IoLibSndFile *self, IoObject *locals, IoMessage *m)
251 size_t channels = IoObject_doubleGetSlot_(self, IOSYMBOL("channels"));
252 UArray *inba = IoSeq_rawUArray(IoMessage_locals_seqArgAt_(m, locals, 0));
253 sf_count_t framesToWrite = UArray_size(inba) / (channels * sizeof(float));
254 sf_count_t framesWritten;
256 IoLibSndFile_openForWriting(self, locals, m);
258 framesWritten = sf_writef_float(DATA(self)->sndfile, (float *)UArray_bytes(inba), framesToWrite);
260 return IONUMBER(framesWritten);