Import existing source tree; original VCS history is no longer available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
529 lines
14 KiB
C
529 lines
14 KiB
C
/*(LGPL)
|
|
---------------------------------------------------------------------------
|
|
a_agw.c - "Algorithmically Generated Waveform" file support
|
|
---------------------------------------------------------------------------
|
|
* Copyright (C) 2002, 2003, David Olofson
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#define DBG(x)
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "kobolog.h"
|
|
#include "config.h"
|
|
#include "eel.h"
|
|
#include "a_types.h"
|
|
#include "a_wca.h"
|
|
#include "a_control.h"
|
|
|
|
|
|
/* Enum class handles */
|
|
|
|
static int enum_aformat, enum_amodtarget, enum_awaveform, enum_afiltertype;
|
|
static int enum_amixmode, enum_aresample;
|
|
|
|
static int enum_pparam, enum_pdriver;
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
AGW Command Callbacks
|
|
----------------------------------------------------------*/
|
|
|
|
static int op_w_reset(int argc, struct eel_data_t *argv)
|
|
{
|
|
DBG(log_printf(D2LOG, "w_reset;\n");)
|
|
wca_reset();
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_format(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
double fs;
|
|
int format = enum_aformat;
|
|
#if 0
|
|
/* Alternative, more verbose method. */
|
|
eel_symbol_t *fmt;
|
|
if(eel_get_args("iEr", &target, &fmt, &fs) != 3)
|
|
return -1;
|
|
if(fmt->token != enum_aformat)
|
|
{
|
|
eel_error("Wrong enum class!");
|
|
return -1;
|
|
}
|
|
DBG(log_printf(D2LOG, "w_format %d, %s, %f;\n", target, eel_s_stringrep(fmt), fs);)
|
|
format = fmt->data.value.i;
|
|
#else
|
|
if(eel_get_args("ier", &target, &format, &fs) != 3)
|
|
return -1;
|
|
#endif
|
|
DBG(log_printf(D2LOG, "w_format %d, %d, %f;\n", target, format, fs);)
|
|
audio_wave_format(target, format, (int)fs);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_gain(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
if(eel_get_args("i", &target) != 1)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_gain %d;\n", target);)
|
|
wca_gain(target);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_convert(int argc, struct eel_data_t *argv)
|
|
{
|
|
int source, target;
|
|
double fs;
|
|
int format = enum_aformat;
|
|
int interpol = enum_aresample;
|
|
argc = eel_get_args("iie[re]",
|
|
&source, &target, &format,
|
|
&fs, &interpol);
|
|
if(argc < 3)
|
|
return -1;
|
|
if(argc < 4)
|
|
fs = 0;
|
|
if(argc < 5)
|
|
interpol = AR_BEST;
|
|
DBG(log_printf(D2LOG, "w_convert %d, %d, %d, %d, %d;\n", source, target,
|
|
format, (int)fs, interpol);)
|
|
audio_wave_convert(source, target, format, (int)fs, interpol);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_enhance(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
double f, level;
|
|
if(eel_get_args("irr", &target, &f, &level) != 3)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_enhance %d, %d, %f;\n", target, (int)f, level);)
|
|
wca_enhance(target, (int)f, level);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_gate(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
double f, min, thres, att;
|
|
if(eel_get_args("irrrr",
|
|
&target, &f, &min, &thres, &att) != 5)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_gate %d, %d, %f, %f, %f;\n",
|
|
target, (int)f, min, thres, att);)
|
|
wca_gate(target, (int)f, min, thres, att);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_blank(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target, loop;
|
|
unsigned samples;
|
|
argc = eel_get_args("ii[i]", &target, &samples, &loop);
|
|
if(argc < 2)
|
|
return -1;
|
|
if(argc < 3)
|
|
loop = 0;
|
|
DBG(log_printf(D2LOG, "w_blank %d, %d, %d;\n", target, samples, loop);)
|
|
audio_wave_blank(target, samples, loop);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_load(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target, loop;
|
|
const char *fn;
|
|
argc = eel_get_args("is[i]", &target, &fn, &loop);
|
|
if(argc < 2)
|
|
return -1;
|
|
if(argc < 3)
|
|
loop = 0;
|
|
DBG(log_printf(D2LOG, "w_load %d, \"%s\", %d;\n", target, fn, loop);)
|
|
if(audio_wave_load(target, fn, loop) < 0)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_save(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
const char *fn;
|
|
if(eel_get_args("is", &target, &fn) != 2)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_save %d, \"%s\";\n", target, fn);)
|
|
if(audio_wave_save(target, fn) < 0)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_prepare(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target;
|
|
if(eel_get_args("i", &target) < 1)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_prepare %d;\n", target);)
|
|
audio_wave_prepare(target);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_env(int argc, struct eel_data_t *argv)
|
|
{
|
|
int i;
|
|
int modtarget = enum_amodtarget;
|
|
double dur[WCA_MAX_ENV_STEPS];
|
|
double val[WCA_MAX_ENV_STEPS];
|
|
|
|
if(argc > 1 + 2*WCA_MAX_ENV_STEPS)
|
|
{
|
|
eel_error("Too many envelope steps!");
|
|
return -1;
|
|
}
|
|
|
|
if(eel_get_args("e[<rr>]", &modtarget, &dur, &val) != argc)
|
|
return -1;
|
|
|
|
DBG(log_printf(D2LOG, "w_env %d", modtarget);)
|
|
wca_mod_reset(modtarget);
|
|
if(2 == argc)
|
|
{
|
|
/*
|
|
* Note that dur[0] actually becomes a *value*
|
|
* rather than a time in this case!
|
|
*/
|
|
DBG(log_printf(D2LOG, ", %f;\n", dur[0]);)
|
|
wca_val(modtarget, dur[0]);
|
|
return 1;
|
|
}
|
|
for(i = 1; i < argc; i += 2)
|
|
{
|
|
int sec = (i-1)/2;
|
|
DBG(log_printf(D2LOG, ", <%f", dur[sec]);)
|
|
if(i+1 >= argc)
|
|
{
|
|
eel_error("<duration, value> argruments must"
|
|
" come in pairs!");
|
|
return -1;
|
|
}
|
|
DBG(else
|
|
log_printf(D2LOG, ", %f", val[sec]);)
|
|
DBG(log_printf(D2LOG, ">");)
|
|
wca_env(modtarget, dur[sec], val[sec]);
|
|
}
|
|
DBG(log_printf(D2LOG, ";\n");)
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_mod(int argc, struct eel_data_t *argv)
|
|
{
|
|
int mt;
|
|
double f, a, d;
|
|
mt = enum_amodtarget;
|
|
if(eel_get_args("errr", &mt, &f, &a, &d) != 4)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_mod %d, %f, %f, %f;\n", mt, f, a, d);)
|
|
wca_mod(mt, f, a, d);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_osc(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target, wf, mm;
|
|
wf = enum_awaveform;
|
|
mm = enum_amixmode;
|
|
switch(eel_get_args("ie[e]", &target, &wf, &mm))
|
|
{
|
|
case 2:
|
|
mm = WCA_ADD;
|
|
case 3:
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
DBG(log_printf(D2LOG, "w_osc %d, %d, %d;\n", target, wf, mm);)
|
|
wca_osc(target, wf, mm);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_w_filter(int argc, struct eel_data_t *argv)
|
|
{
|
|
int target, ft;
|
|
ft = enum_afiltertype;
|
|
if(eel_get_args("ie", &target, &ft) != 2)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "w_filter %d, %d;\n", target, ft);)
|
|
wca_filter(target, ft);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Patch Command Callbacks
|
|
----------------------------------------------------------*/
|
|
|
|
static int op_p_param(int argc, struct eel_data_t *argv)
|
|
{
|
|
int patch, param;
|
|
double value;
|
|
param = enum_pparam;
|
|
if(eel_get_args("ier", &patch, ¶m, &value) != 3)
|
|
return -1;
|
|
switch(param)
|
|
{
|
|
case APP_DRIVER:
|
|
case APP_WAVE:
|
|
case APP_ENV_SKIP:
|
|
case APP_LFO_SHAPE:
|
|
audio_patch_param(patch, param, (int)value);
|
|
break;
|
|
default:
|
|
audio_patch_param(patch, param, (int)(value * 65536.0));
|
|
break;
|
|
}
|
|
DBG(log_printf(D2LOG, "p_param %d, %d, %f;\n", patch, param, value);)
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int op_p_driver(int argc, struct eel_data_t *argv)
|
|
{
|
|
int patch;
|
|
eel_symbol_t *callback;
|
|
if(eel_get_args("if", &patch, &callback) != 2)
|
|
return -1;
|
|
DBG(log_printf(D2LOG, "p_driver %d, %s;\n", patch, eel_s_stringrep(callback));)
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Init code
|
|
----------------------------------------------------------*/
|
|
|
|
static void load_keywords(void)
|
|
{
|
|
/* WCA calls */
|
|
eel_register_operator("w_reset", op_w_reset, 100, 0 ,0);
|
|
eel_register_operator("w_format", op_w_format, 100, 0 ,0);
|
|
eel_register_operator("w_blank", op_w_blank, 100, 0 ,0);
|
|
eel_register_operator("w_load", op_w_load, 100, 0 ,0);
|
|
eel_register_operator("w_save", op_w_save, 100, 0 ,0);
|
|
eel_register_operator("w_prepare", op_w_prepare, 100, 0 ,0);
|
|
eel_register_operator("w_env", op_w_env, 100, 0 ,0);
|
|
eel_register_operator("w_mod", op_w_mod, 100, 0 ,0);
|
|
eel_register_operator("w_osc", op_w_osc, 100, 0 ,0);
|
|
eel_register_operator("w_filter", op_w_filter, 100, 0 ,0);
|
|
eel_register_operator("w_gain", op_w_gain, 100, 0 ,0);
|
|
eel_register_operator("w_convert", op_w_convert, 100, 0 ,0);
|
|
eel_register_operator("w_enhance", op_w_enhance, 100, 0 ,0);
|
|
eel_register_operator("w_gate", op_w_gate, 100, 0 ,0);
|
|
|
|
/* w_convert resampling modes */
|
|
enum_aresample = eel_register_enum_class();
|
|
eel_register_enum(enum_aresample, "NEAREST", AR_NEAREST);
|
|
eel_register_enum(enum_aresample, "NEAREST4X", AR_NEAREST_4X);
|
|
eel_register_enum(enum_aresample, "LINEAR", AR_LINEAR);
|
|
eel_register_enum(enum_aresample, "LINEAR2X", AR_LINEAR_2X_R);
|
|
eel_register_enum(enum_aresample, "LINEAR4X", AR_LINEAR_4X_R);
|
|
eel_register_enum(enum_aresample, "LINEAR8X", AR_LINEAR_8X_R);
|
|
eel_register_enum(enum_aresample, "LINEAR16X", AR_LINEAR_16X_R);
|
|
eel_register_enum(enum_aresample, "CUBIC", AR_CUBIC_R);
|
|
|
|
eel_register_enum(enum_aresample, "WORST", AR_WORST);
|
|
eel_register_enum(enum_aresample, "MEDIUM", AR_MEDIUM);
|
|
eel_register_enum(enum_aresample, "BEST", AR_BEST);
|
|
|
|
/* Sample formats */
|
|
enum_aformat = eel_register_enum_class();
|
|
eel_register_enum(enum_aformat, "MONO8", AF_MONO8);
|
|
eel_register_enum(enum_aformat, "STEREO8", AF_STEREO8);
|
|
eel_register_enum(enum_aformat, "MONO16", AF_MONO16);
|
|
eel_register_enum(enum_aformat, "STEREO16", AF_STEREO16);
|
|
eel_register_enum(enum_aformat, "MONO32", AF_MONO32);
|
|
eel_register_enum(enum_aformat, "STEREO32", AF_STEREO32);
|
|
|
|
/* Modulation targets */
|
|
enum_amodtarget = eel_register_enum_class();
|
|
eel_register_enum(enum_amodtarget, "AMPLITUDE", WCA_AMPLITUDE);
|
|
eel_register_enum(enum_amodtarget, "BALANCE", WCA_BALANCE);
|
|
eel_register_enum(enum_amodtarget, "FREQUENCY", WCA_FREQUENCY);
|
|
eel_register_enum(enum_amodtarget, "LIMIT", WCA_LIMIT);
|
|
eel_register_enum(enum_amodtarget, "MOD1", WCA_MOD1);
|
|
eel_register_enum(enum_amodtarget, "MOD2", WCA_MOD2);
|
|
eel_register_enum(enum_amodtarget, "MOD3", WCA_MOD3);
|
|
|
|
/* Oscillator output modes */
|
|
enum_amixmode = eel_register_enum_class();
|
|
eel_register_enum(enum_amixmode, "ADD", WCA_ADD);
|
|
eel_register_enum(enum_amixmode, "MUL", WCA_MUL);
|
|
eel_register_enum(enum_amixmode, "FM", WCA_FM);
|
|
eel_register_enum(enum_amixmode, "FM_ADD", WCA_FM_ADD);
|
|
eel_register_enum(enum_amixmode, "SYNC", WCA_SYNC);
|
|
eel_register_enum(enum_amixmode, "SYNC_ADD", WCA_SYNC_ADD);
|
|
|
|
/* Oscillator waveforms */
|
|
enum_awaveform = eel_register_enum_class();
|
|
eel_register_enum(enum_awaveform, "DC", WCA_DC);
|
|
eel_register_enum(enum_awaveform, "SINE", WCA_SINE);
|
|
eel_register_enum(enum_awaveform, "HALFSINE", WCA_HALFSINE);
|
|
eel_register_enum(enum_awaveform, "RECTSINE", WCA_RECTSINE);
|
|
eel_register_enum(enum_awaveform, "SINEMORPH", WCA_SINEMORPH);
|
|
eel_register_enum(enum_awaveform, "BLMORPH", WCA_BLMORPH);
|
|
eel_register_enum(enum_awaveform, "BLCROSS", WCA_BLCROSS);
|
|
eel_register_enum(enum_awaveform, "PULSE", WCA_PULSE);
|
|
eel_register_enum(enum_awaveform, "TRIANGLE", WCA_TRIANGLE);
|
|
eel_register_enum(enum_awaveform, "NOISE", WCA_NOISE);
|
|
eel_register_enum(enum_awaveform, "SPECTRUM", WCA_SPECTRUM);
|
|
eel_register_enum(enum_awaveform, "ASPECTRUM", WCA_ASPECTRUM);
|
|
eel_register_enum(enum_awaveform, "HSPECTRUM", WCA_HSPECTRUM);
|
|
eel_register_enum(enum_awaveform, "AHSPECTRUM", WCA_AHSPECTRUM);
|
|
|
|
/* Filter types */
|
|
enum_afiltertype = eel_register_enum_class();
|
|
eel_register_enum(enum_afiltertype, "ALLPASS", WCA_ALLPASS);
|
|
eel_register_enum(enum_afiltertype, "LOWPASS_6", WCA_LOWPASS_6DB);
|
|
eel_register_enum(enum_afiltertype, "HIGHPASS_6", WCA_HIGHPASS_6DB);
|
|
eel_register_enum(enum_afiltertype, "LOWPASS_12", WCA_LOWPASS_12DB);
|
|
eel_register_enum(enum_afiltertype, "HIGHPASS_12", WCA_HIGHPASS_12DB);
|
|
eel_register_enum(enum_afiltertype, "BANDPASS_12", WCA_BANDPASS_12DB);
|
|
eel_register_enum(enum_afiltertype, "NOTCH_12", WCA_NOTCH_12DB);
|
|
eel_register_enum(enum_afiltertype, "PEAK_12", WCA_PEAK_12DB);
|
|
|
|
/* Patch calls */
|
|
eel_register_operator("p_param", op_p_param, 100, 0 ,0);
|
|
eel_register_operator("p_driver", op_p_driver, 100, 0 ,0);
|
|
|
|
/* Patch Parameters */
|
|
enum_pparam = eel_register_enum_class();
|
|
eel_register_enum(enum_pparam, "DRIVER", APP_DRIVER);
|
|
eel_register_enum(enum_pparam, "WAVE", APP_WAVE);
|
|
eel_register_enum(enum_pparam, "RANDPITCH", APP_RANDPITCH);
|
|
eel_register_enum(enum_pparam, "RANDVOL", APP_RANDVOL);
|
|
|
|
eel_register_enum(enum_pparam, "ENV_SKIP", APP_ENV_SKIP);
|
|
eel_register_enum(enum_pparam, "ENV_L0", APP_ENV_L0);
|
|
eel_register_enum(enum_pparam, "ENV_DELAY", APP_ENV_DELAY);
|
|
eel_register_enum(enum_pparam, "ENV_T1", APP_ENV_T1);
|
|
eel_register_enum(enum_pparam, "ENV_L1", APP_ENV_L1);
|
|
eel_register_enum(enum_pparam, "ENV_HOLD", APP_ENV_HOLD);
|
|
eel_register_enum(enum_pparam, "ENV_T2", APP_ENV_T2);
|
|
eel_register_enum(enum_pparam, "ENV_L2", APP_ENV_L2);
|
|
eel_register_enum(enum_pparam, "ENV_T3", APP_ENV_T3);
|
|
eel_register_enum(enum_pparam, "ENV_T4", APP_ENV_T4);
|
|
|
|
/* Patch Drivers */
|
|
enum_pdriver = eel_register_enum_class();
|
|
eel_register_enum(enum_pdriver, "MONO", PD_MONO);
|
|
eel_register_enum(enum_pdriver, "POLY", PD_POLY);
|
|
eel_register_enum(enum_pdriver, "MIDI", PD_MIDI);
|
|
eel_register_enum(enum_pdriver, "EEL", PD_EEL);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
API code
|
|
----------------------------------------------------------*/
|
|
|
|
static int _agw_initialized = 0;
|
|
|
|
|
|
int agw_open(void)
|
|
{
|
|
if(_agw_initialized)
|
|
return 0;
|
|
|
|
eel_open();
|
|
|
|
eel_push_scope(); /* begin AGW extensions scope */
|
|
|
|
load_keywords();
|
|
|
|
/* Built-in variables */
|
|
(void)eel_set_integer("target", -1);
|
|
|
|
_agw_initialized = 1;
|
|
return 0;
|
|
}
|
|
|
|
void agw_close(void)
|
|
{
|
|
if(!_agw_initialized)
|
|
return;
|
|
|
|
eel_pop_scope(); /* end AGW extensions scope */
|
|
|
|
eel_close();
|
|
|
|
_agw_initialized = 0;
|
|
}
|
|
|
|
#define CHECKINIT if(!_agw_initialized) agw_open();
|
|
|
|
int agw_load(int wid, const char *name)
|
|
{
|
|
int script, res;
|
|
|
|
CHECKINIT
|
|
|
|
if(wid < 0)
|
|
{
|
|
wid = audio_wave_alloc(wid);
|
|
if(wid < 0)
|
|
return wid;
|
|
}
|
|
|
|
script = eel_load(name);
|
|
if(script < 0)
|
|
return -1;
|
|
|
|
eel_push_scope(); /* begin script scope */
|
|
|
|
/* Initialize "argument" variables */
|
|
(void)eel_set_integer("target", wid);
|
|
|
|
/* Reset the waveform construction engine */
|
|
wca_reset();
|
|
|
|
res = eel_run(script);
|
|
eel_free(script);
|
|
|
|
eel_pop_scope(); /* end script scope */
|
|
|
|
if(res < 0)
|
|
return -1;
|
|
|
|
audio_wave_prepare(wid);
|
|
|
|
return wid;
|
|
}
|