1 /*
2 Audio File Library
3 Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
4 Copyright (C) 2000, Silicon Graphics, Inc.
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301 USA
20 */
21
22 /*
23 Instrument.cpp
24
25 Info about instrument parameters:
26
27 Each unit has an array of _InstParamInfo structures, one for
28 each instrument parameter. Each of these structures describes
29 the inst parameters.
30
31 id: a 4-byte id as in AIFF file
32 type: data type AU_PVLIST_*
33 name: text name
34 defaultValue: default value, to which it is set when a file with
35 instruments is first opened for writing.
36
37 Each inst has only an array of values (_AFPVu's). Each value in the
38 instrument's array is the value of the corresponding index into the
39 unit's instparaminfo array.
40
41 So for a unit u and an instrument i, u.instparam[N] describes
42 the parameter whose value is given in i.value[N].
43 */
44
45 #include "config.h"
46
47 #include "FileHandle.h"
48 #include "Instrument.h"
49 #include "Setup.h"
50 #include "afinternal.h"
51 #include "audiofile.h"
52 #include "units.h"
53 #include "util.h"
54
55 #include <stdlib.h>
56
allocateLoops(int count)57 bool InstrumentSetup::allocateLoops(int count)
58 {
59 freeLoops();
60 loops = (LoopSetup *) _af_calloc(count, sizeof (LoopSetup));
61 if (loops)
62 {
63 loopCount = count;
64 return true;
65 }
66 return false;
67 }
68
freeLoops()69 void InstrumentSetup::freeLoops()
70 {
71 if (loops)
72 free(loops);
73 loops = NULL;
74 loopCount = 0;
75 }
76
77 /*
78 Initialize instrument id list for audio file.
79 */
afInitInstIDs(AFfilesetup setup,const int * instids,int ninsts)80 void afInitInstIDs (AFfilesetup setup, const int *instids, int ninsts)
81 {
82 if (!_af_filesetup_ok(setup))
83 return;
84
85 if (!_af_unique_ids(instids, ninsts, "instrument", AF_BAD_INSTID))
86 return;
87
88 _af_setup_free_instruments(setup);
89
90 setup->instrumentCount = ninsts;
91 setup->instrumentSet = true;
92
93 setup->instruments = _af_instsetup_new(setup->instrumentCount);
94
95 for (int i=0; i < setup->instrumentCount; i++)
96 setup->instruments[i].id = instids[i];
97 }
98
afGetInstIDs(AFfilehandle file,int * instids)99 int afGetInstIDs (AFfilehandle file, int *instids)
100 {
101 if (!_af_filehandle_ok(file))
102 return -1;
103
104 if (instids)
105 for (int i=0; i < file->m_instrumentCount; i++)
106 instids[i] = file->m_instruments[i].id;
107
108 return file->m_instrumentCount;
109 }
110
111 /*
112 This routine checks and sets instrument parameters.
113 npv is number of valid AUpvlist pairs.
114 */
_af_instparam_set(AFfilehandle file,int instid,AUpvlist pvlist,int npv)115 void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
116 {
117 if (!_af_filehandle_ok(file))
118 return;
119
120 if (!file->checkCanWrite())
121 return;
122
123 Instrument *instrument = file->getInstrument(instid);
124 if (!instrument)
125 return;
126
127 if (AUpvgetmaxitems(pvlist) < npv)
128 npv = AUpvgetmaxitems(pvlist);
129
130 for (int i=0; i < npv; i++)
131 {
132 int param;
133
134 AUpvgetparam(pvlist, i, ¶m);
135
136 int j;
137 if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
138 /* no parameter with that id; ignore */
139 continue;
140
141 if (!file->isInstrumentParameterValid(pvlist, i))
142 /* bad parameter value; ignore */
143 continue;
144
145 int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
146
147 switch (type)
148 {
149 case AU_PVTYPE_LONG:
150 AUpvgetval(pvlist, i, &instrument->values[j].l);
151 break;
152 case AU_PVTYPE_DOUBLE:
153 AUpvgetval(pvlist, i, &instrument->values[j].d);
154 break;
155 case AU_PVTYPE_PTR:
156 AUpvgetval(pvlist, i, &instrument->values[j].v);
157 break;
158 default:
159 return;
160 }
161 }
162 }
163
afSetInstParams(AFfilehandle file,int instid,AUpvlist pvlist,int npv)164 void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
165 {
166 _af_instparam_set(file, instid, pvlist, npv);
167 }
168
afSetInstParamLong(AFfilehandle file,int instid,int param,long value)169 void afSetInstParamLong (AFfilehandle file, int instid, int param, long value)
170 {
171 AUpvlist pvlist = AUpvnew(1);
172
173 AUpvsetparam(pvlist, 0, param);
174 AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
175 AUpvsetval(pvlist, 0, &value);
176
177 _af_instparam_set(file, instid, pvlist, 1);
178
179 AUpvfree(pvlist);
180 }
181
182 /*
183 This routine gets instrument parameters.
184 npv is number of valid AUpvlist pairs
185 */
_af_instparam_get(AFfilehandle file,int instid,AUpvlist pvlist,int npv,bool forceLong)186 void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist, int npv,
187 bool forceLong)
188 {
189 if (!_af_filehandle_ok(file))
190 return;
191
192 Instrument *instrument = file->getInstrument(instid);
193 if (!instrument)
194 return;
195
196 if (AUpvgetmaxitems(pvlist) < npv)
197 npv = AUpvgetmaxitems(pvlist);
198
199 for (int i=0; i < npv; i++)
200 {
201 int param;
202 AUpvgetparam(pvlist, i, ¶m);
203
204 int j;
205 if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
206 /* no parameter with that id; ignore */
207 continue;
208
209 int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
210
211 /*
212 forceLong is true when this routine called by
213 afGetInstParamLong().
214 */
215 if (forceLong && type != AU_PVTYPE_LONG)
216 {
217 _af_error(AF_BAD_INSTPTYPE, "type of instrument parameter %d is not AU_PVTYPE_LONG", param);
218 continue;
219 }
220
221 AUpvsetvaltype(pvlist, i, type);
222
223 switch (type)
224 {
225 case AU_PVTYPE_LONG:
226 AUpvsetval(pvlist, i, &instrument->values[j].l);
227 break;
228 case AU_PVTYPE_DOUBLE:
229 AUpvsetval(pvlist, i, &instrument->values[j].d);
230 break;
231 case AU_PVTYPE_PTR:
232 AUpvsetval(pvlist, i, &instrument->values[j].v);
233 break;
234
235 default:
236 _af_error(AF_BAD_INSTPTYPE, "invalid instrument parameter type %d", type);
237 return;
238 }
239 }
240 }
241
242 /*
243 afGetInstParams -- get a parameter-value array containing
244 instrument parameters for the specified instrument chunk
245 */
afGetInstParams(AFfilehandle file,int inst,AUpvlist pvlist,int npv)246 void afGetInstParams (AFfilehandle file, int inst, AUpvlist pvlist, int npv)
247 {
248 _af_instparam_get(file, inst, pvlist, npv, false);
249 }
250
afGetInstParamLong(AFfilehandle file,int inst,int param)251 long afGetInstParamLong (AFfilehandle file, int inst, int param)
252 {
253 long val;
254 AUpvlist pvlist = AUpvnew(1);
255
256 AUpvsetparam(pvlist, 0, param);
257 AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
258
259 _af_instparam_get(file, inst, pvlist, 1, true);
260
261 AUpvgetval(pvlist, 0, &val);
262 AUpvfree(pvlist);
263
264 return(val);
265 }
266
267 /*
268 Search _af_units[fileFormat].instrumentParameters for the instrument
269 parameter with the specified id.
270
271 Report an error and return -1 if no such instrument parameter
272 exists.
273 */
274
_af_instparam_index_from_id(int filefmt,int id)275 int _af_instparam_index_from_id (int filefmt, int id)
276 {
277 int i;
278
279 for (i = 0; i < _af_units[filefmt].instrumentParameterCount; i++)
280 if (_af_units[filefmt].instrumentParameters[i].id == id)
281 break;
282
283 if (i == _af_units[filefmt].instrumentParameterCount)
284 {
285 _af_error(AF_BAD_INSTPID, "invalid instrument parameter id %d",
286 id);
287 return -1;
288 }
289
290 return i;
291 }
292
getLoop(int loopID)293 Loop *Instrument::getLoop(int loopID)
294 {
295 for (int i=0; i<loopCount; i++)
296 if (loops[i].id == loopID)
297 return &loops[i];
298
299 _af_error(AF_BAD_LOOPID, "no loop with id %d for instrument %d\n",
300 loopID, id);
301 return NULL;
302 }
303