2 * libremix -- An audio mixing and sequencing library.
4 * Copyright (C) 2001 Commonwealth Scientific and Industrial Research
5 * Organisation (CSIRO), Australia.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * RemixBase: A generic interface for sound generation and processing.
26 * Conrad Parker <conrad@metadecks.org>, August 2001
36 remix_new (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters)
40 if (plugin == RemixNone) {
41 remix_set_error (env, REMIX_ERROR_NOENTITY);
45 base = remix_base_new (env);
47 if (base == RemixNone) {
48 remix_set_error (env, REMIX_ERROR_NOENTITY);
52 base->plugin = plugin;
54 if (plugin->init != NULL) {
55 if (plugin->init (env, base, parameters) == RemixNone) {
56 remix_destroy (env, base);
65 remix_suggest (RemixEnv * env, RemixPlugin * plugin, CDSet * parameters)
67 if (plugin == RemixNone) {
68 remix_set_error (env, REMIX_ERROR_NOENTITY);
72 if (!plugin->suggest) {
73 /* XXX: should remix_set_error: is NOOP appropriate ?? */
77 return plugin->suggest (env, plugin, parameters, plugin->plugin_data);
81 remix_parameter_scheme_get_key (RemixEnv * env, CDSet * scheme_set, char * name)
84 RemixParameterScheme * scheme;
86 for (s = scheme_set; s; s = s->next) {
87 scheme = (RemixParameterScheme *)s->data.s_pointer;
88 if (!strcmp (scheme->name, name)) return s->key;
91 remix_set_error (env, REMIX_ERROR_NOENTITY);
97 remix_get_init_parameter_key (RemixEnv * env, RemixPlugin * plugin, char * name)
99 if (plugin == RemixNone) {
100 remix_dprintf ("[remix_get_init_parameter_key] plugin == RemixNone\n");
101 remix_set_error (env, REMIX_ERROR_NOENTITY);
105 return remix_parameter_scheme_get_key (env, plugin->init_scheme, name);
109 remix_get_parameter_key (RemixEnv * env, RemixBase * base, char * name)
111 if (base == RemixNone) {
112 remix_dprintf ("[remix_get_parameter_key] base == RemixNone\n");
113 remix_set_error (env, REMIX_ERROR_NOENTITY);
117 if (base->plugin == RemixNone) {
118 remix_dprintf ("[remix_get_parameter_key] base->plugin == RemixNone\n");
119 remix_set_error (env, REMIX_ERROR_NOENTITY);
123 return remix_parameter_scheme_get_key (env, base->plugin->process_scheme, name);
127 remix_set_parameter (RemixEnv * env, RemixBase * base, int key,
128 RemixParameter parameter)
130 if (base == RemixNone) {
131 remix_dprintf ("[remix_set_parameter] base == RemixNone\n");
132 remix_set_error (env, REMIX_ERROR_NOENTITY);
133 return (RemixParameter)-1;
136 remix_dprintf ("[remix_set_parameter] base %p, [%d] ==> %p\n", base, key,
137 parameter.s_pointer);
138 base->parameters = cd_set_replace (env, base->parameters, key, parameter);
143 remix_get_parameter (RemixEnv * env, RemixBase * base, int key)
147 if (base == RemixNone) {
148 remix_dprintf ("[remix_get_parameter] base == RemixNone\n");
149 remix_set_error (env, REMIX_ERROR_NOENTITY);
150 return (RemixParameter)-1;
153 p = cd_set_find (env, base->parameters, key);
154 remix_dprintf ("[remix_get_parameter] base %p, [%d] == %p\n", base, key,
160 remix_get_parameter_type (RemixEnv * env, RemixBase * base, int key)
162 RemixPlugin * plugin;
164 RemixParameterScheme * scheme;
166 if (base == RemixNone) {
167 remix_dprintf ("[remix_get_parameter_type] base == RemixNone\n");
168 remix_set_error (env, REMIX_ERROR_NOENTITY);
172 plugin = base->plugin;
174 if (plugin == RemixNone) {
175 remix_dprintf ("[remix_get_parameter_type] base->plugin == RemixNone\n");
176 remix_set_error (env, REMIX_ERROR_NOENTITY);
180 k = cd_set_find (env, plugin->process_scheme, key);
181 scheme = (RemixParameterScheme *)k.s_pointer;
183 if (scheme == RemixNone) {
184 remix_dprintf ("[remix_get_parameter_type] scheme == RemixNone\n");
185 remix_set_error (env, REMIX_ERROR_NOENTITY);
193 remix_base_new_subclass (RemixEnv * env, size_t size)
195 RemixBase * base = remix_malloc (size);
196 _remix_context_copy (env, &base->context_limit);
197 _remix_register_base (env, base);
202 remix_base_new (RemixEnv * env)
204 return remix_base_new_subclass (env, sizeof (struct _RemixBase));
208 remix_base_get_mixlength (RemixEnv * env, RemixBase * base)
210 if (base == RemixNone) {
211 remix_set_error (env, REMIX_ERROR_NOENTITY);
215 return _remix_base_get_mixlength (env, base);
219 remix_base_get_samplerate (RemixEnv * env, RemixBase * base)
221 if (base == RemixNone) {
222 remix_set_error (env, REMIX_ERROR_NOENTITY);
226 return _remix_base_get_samplerate (env, base);
230 remix_base_get_tempo (RemixEnv * env, RemixBase * base)
232 if (base == RemixNone) {
233 remix_set_error (env, REMIX_ERROR_NOENTITY);
237 return _remix_base_get_tempo (env, base);
241 remix_base_get_channels (RemixEnv * env, RemixBase * base)
243 if (base == RemixNone) {
244 remix_set_error (env, REMIX_ERROR_NOENTITY);
248 return _remix_base_get_channels (env, base);
252 remix_base_set_instance_data (RemixEnv * env, RemixBase * base, void * data)
254 if (base == RemixNone) {
255 remix_set_error (env, REMIX_ERROR_NOENTITY);
259 return _remix_set_instance_data (env, base, data);
263 remix_base_get_instance_data (RemixEnv * env, RemixBase * base)
265 if (base == RemixNone) {
266 remix_set_error (env, REMIX_ERROR_NOENTITY);
270 return _remix_get_instance_data (env, base);
274 remix_base_has_samplerate (RemixEnv * env, RemixBase * base)
276 RemixSamplerate asr, bsr;
278 asr = remix_get_samplerate (env);
279 bsr = _remix_base_get_samplerate (env, base);
285 remix_base_has_tempo (RemixEnv * env, RemixBase * base)
289 at = remix_get_tempo (env);
290 bt = _remix_base_get_tempo (env, base);
296 remix_base_encompasses_mixlength (RemixEnv * env, RemixBase * base)
300 aml = remix_get_mixlength (env);
301 bml = _remix_base_get_mixlength (env, base);
307 remix_base_encompasses_channels (RemixEnv * env, RemixBase * base)
309 CDSet * s, * as, * bs;
312 as = remix_get_channels (env);
313 bs = _remix_base_get_channels (env, base);
315 for (s = as; s; s = s->next) {
316 k = cd_set_find (env, bs, s->key);
317 if (k.s_pointer == NULL) return 0;
324 remix_base_set_methods (RemixEnv * env, RemixBase * base, RemixMethods * methods)
326 RemixMethods * old = base->methods;
327 _remix_set_methods (env, base, methods);
332 remix_base_get_methods (RemixEnv * env, RemixBase * base)
334 return _remix_get_methods (env, base);
338 remix_base_set_plugin (RemixEnv * env, RemixBase * base, RemixPlugin * plugin)
340 RemixPlugin * old = base->plugin;
341 _remix_set_plugin (env, base, plugin);
346 remix_base_get_plugin (RemixEnv * env, RemixBase * base)
348 return _remix_get_plugin (env, base);
352 remix_clone_subclass (RemixEnv * env, RemixBase * base)
355 remix_set_error (env, REMIX_ERROR_NOENTITY);
358 if (!base->methods || !base->methods->clone) {
359 remix_set_error (env, REMIX_ERROR_INVALID);
362 return _remix_clone (env, base);
366 remix_destroy (RemixEnv * env, RemixBase * base)
369 remix_set_error (env, REMIX_ERROR_NOENTITY);
373 _remix_unregister_base (env, base);
375 if (!base->methods || !base->methods->destroy) {
376 remix_set_error (env, REMIX_ERROR_INVALID);
379 return _remix_destroy (env, base);
383 remix_destroy_list (RemixEnv * env, CDList * list)
385 cd_list_destroy_with (env, list, (CDDestroyFunc)remix_destroy);
390 * Prepare the methods for process, seek and length calls.
392 * "Prepare" means to make sure the base has enough internal buffers
393 * to deal with the current context (sample rate, mixlength).
395 * If the methods has a ready() function, that is checked first. If it
396 * does not have a ready() function, it is assumed to always be ready.
399 remix_prepare (RemixEnv * env, RemixBase * base)
404 remix_set_error (env, REMIX_ERROR_NOENTITY);
407 if (base->methods && base->methods->prepare) {
408 if (base->methods->ready) {
409 is_ready = base->methods->ready (env, base);
412 _remix_context_merge (env, &base->context_limit);
414 if (!is_ready) base =_remix_prepare (env, base);
421 remix_process_fast (RemixEnv * env, RemixBase * base, RemixCount count,
422 RemixStream * input, RemixStream * output)
427 remix_set_error (env, REMIX_ERROR_NOENTITY);
430 if (!base->methods || !base->methods->process) {
431 remix_set_error (env, REMIX_ERROR_INVALID);
434 n = _remix_process (env, base, count, input, output);
435 if (n > 0) base->offset += n;
440 remix_process (RemixEnv * env, RemixBase * base, RemixCount count,
441 RemixStream * input, RemixStream * output)
443 RemixCount processed;
450 processed = remix_process_fast (env, base, count, input, output);
452 if (processed == -1) {
453 error = remix_last_error (env);
454 str = remix_error_string (env, error);
455 remix_dprintf ("*** ERROR in remix_process: %s\n", str);
457 case REMIX_ERROR_NOOP:
458 n = remix_stream_write (env, output, count, input);
464 case REMIX_ERROR_SILENCE:
465 n = remix_stream_write0 (env, output, count);
481 remix_length (RemixEnv * env, RemixBase * base)
484 remix_set_error (env, REMIX_ERROR_NOENTITY);
487 if (!base->methods || !base->methods->length) {
488 remix_set_error (env, REMIX_ERROR_INVALID);
491 return _remix_length (env, base);
495 remix_seek (RemixEnv * env, RemixBase * base, RemixCount offset, int whence)
497 RemixCount new_offset, len;
500 remix_set_error (env, REMIX_ERROR_NOENTITY);
504 new_offset = base->offset;
507 case SEEK_SET: new_offset = offset; break;
508 case SEEK_CUR: new_offset += offset; break;
510 len = remix_length (env, base);
511 if (len == -1) return -1;
512 new_offset = len + offset;
515 remix_set_error (env, REMIX_ERROR_INVALID);
520 if (new_offset == base->offset) return new_offset;
522 remix_dprintf ("SEEK %p @ %ld\n", base, new_offset);
524 if (base->methods && base->methods->seek)
525 base->offset = base->methods->seek (env, base, new_offset);
527 base->offset = new_offset;
533 remix_tell (RemixEnv * env, RemixBase * base)
536 remix_set_error (env, REMIX_ERROR_NOENTITY);
543 remix_flush (RemixEnv * env, RemixBase * base)
546 remix_set_error (env, REMIX_ERROR_NOENTITY);
549 if (!base->methods || !base->methods->flush) {
550 remix_set_error (env, REMIX_ERROR_INVALID);
553 return _remix_flush (env, base);
557 remix_get_meta_text (RemixEnv * env, RemixBase * base)
559 RemixPlugin * plugin = base->plugin;
560 return (plugin ? plugin->metatext : NULL);
564 remix_set_meta_text (RemixEnv * env, RemixBase * base, RemixMetaText * mt)
566 RemixPlugin * plugin;
569 if (base == RemixNone) {
570 remix_set_error (env, REMIX_ERROR_NOENTITY);
574 plugin = base->plugin;
575 if (plugin == RemixNone) {
576 remix_set_error (env, REMIX_ERROR_NOENTITY);
580 old = plugin->metatext;
581 plugin->metatext = mt;
586 remix_is_writeable (RemixEnv * env, RemixBase * base)
588 RemixPlugin * plugin;
590 if (base == RemixNone) {
591 remix_set_error (env, REMIX_ERROR_NOENTITY);
595 plugin = base->plugin;
596 if (plugin == RemixNone) {
597 remix_set_error (env, REMIX_ERROR_NOENTITY);
601 return (plugin->flags & REMIX_PLUGIN_WRITEABLE);
605 remix_is_seekable (RemixEnv * env, RemixBase * base)
607 RemixPlugin * plugin;
609 if (base == RemixNone) {
610 remix_set_error (env, REMIX_ERROR_NOENTITY);
614 plugin = base->plugin;
615 if (plugin == RemixNone) {
616 remix_set_error (env, REMIX_ERROR_NOENTITY);
620 return (plugin->flags & REMIX_PLUGIN_SEEKABLE);
624 remix_is_cacheable (RemixEnv * env, RemixBase * base)
626 RemixPlugin * plugin;
628 if (base == RemixNone) {
629 remix_set_error (env, REMIX_ERROR_NOENTITY);
633 plugin = base->plugin;
634 if (plugin == RemixNone) {
635 remix_set_error (env, REMIX_ERROR_NOENTITY);
639 return (plugin->flags & REMIX_PLUGIN_CACHEABLE);
643 remix_is_causal (RemixEnv * env, RemixBase * base)
645 RemixPlugin * plugin;
647 if (base == RemixNone) {
648 remix_set_error (env, REMIX_ERROR_NOENTITY);
652 plugin = base->plugin;
653 if (plugin == RemixNone) {
654 remix_set_error (env, REMIX_ERROR_NOENTITY);
658 return (plugin->flags & REMIX_PLUGIN_CAUSAL);