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, &param);
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, &param);
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