1 /* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /* trivial_synth.c
4 
5    DSSI Soft Synth Interface
6    Constructed by Chris Cannam, Steve Harris and Sean Bolton
7 
8    This is an example DSSI synth plugin written by Steve Harris.
9 
10    This example file is in the public domain.
11 */
12 
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <math.h>
17 #include <stdio.h>
18 
19 #include "dssi.h"
20 #include "ladspa.h"
21 
22 #define TS_OUTPUT 0
23 #define TS_FREQ   1
24 #define TS_VOLUME 2
25 
26 #define MIDI_NOTES 128
27 
28 static LADSPA_Descriptor *tsLDescriptor = NULL;
29 static DSSI_Descriptor *tsDDescriptor = NULL;
30 
31 static void runTS(LADSPA_Handle instance, unsigned long sample_count,
32 		  snd_seq_event_t * events, unsigned long EventCount);
33 
34 typedef struct {
35     unsigned int active;
36     float amp;
37     double phase;
38 } note_data;
39 
40 typedef struct {
41     LADSPA_Data *output;
42     LADSPA_Data *freq;
43     LADSPA_Data *vol;
44     note_data data[MIDI_NOTES];
45     float omega[MIDI_NOTES];
46 } TS;
47 
ladspa_descriptor(unsigned long index)48 const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
49 {
50     switch (index) {
51     case 0:
52 	return tsLDescriptor;
53     default:
54 	return NULL;
55     }
56 }
57 
dssi_descriptor(unsigned long index)58 const DSSI_Descriptor *dssi_descriptor(unsigned long index)
59 {
60     switch (index) {
61     case 0:
62 	return tsDDescriptor;
63     default:
64 	return NULL;
65     }
66 }
67 
cleanupTS(LADSPA_Handle instance)68 static void cleanupTS(LADSPA_Handle instance)
69 {
70     free(instance);
71 }
72 
connectPortTS(LADSPA_Handle instance,unsigned long port,LADSPA_Data * data)73 static void connectPortTS(LADSPA_Handle instance, unsigned long port,
74 			  LADSPA_Data * data)
75 {
76     TS *plugin;
77 
78     plugin = (TS *) instance;
79     switch (port) {
80     case TS_OUTPUT:
81 	plugin->output = data;
82 	break;
83     case TS_FREQ:
84 	plugin->freq = data;
85 	break;
86     case TS_VOLUME:
87 	plugin->vol = data;
88 	break;
89     }
90 }
91 
instantiateTS(const LADSPA_Descriptor * descriptor,unsigned long s_rate)92 static LADSPA_Handle instantiateTS(const LADSPA_Descriptor * descriptor,
93 				   unsigned long s_rate)
94 {
95     unsigned int i;
96 
97     TS *plugin_data = (TS *) malloc(sizeof(TS));
98     for (i=0; i<MIDI_NOTES; i++) {
99 	    plugin_data->omega[i] = M_PI * 2.0 / (double)s_rate *
100 				    pow(2.0, (i-69.0) / 12.0);
101     }
102 
103     return (LADSPA_Handle) plugin_data;
104 }
105 
activateTS(LADSPA_Handle instance)106 static void activateTS(LADSPA_Handle instance)
107 {
108     TS *plugin_data = (TS *) instance;
109     unsigned int i;
110 
111     for (i=0; i<MIDI_NOTES; i++) {
112 	plugin_data->data[i].active = 0;
113     }
114 }
115 
runTSWrapper(LADSPA_Handle instance,unsigned long sample_count)116 static void runTSWrapper(LADSPA_Handle instance,
117 			 unsigned long sample_count)
118 {
119     runTS(instance, sample_count, NULL, 0);
120 }
121 
runTS(LADSPA_Handle instance,unsigned long sample_count,snd_seq_event_t * events,unsigned long event_count)122 static void runTS(LADSPA_Handle instance, unsigned long sample_count,
123 		  snd_seq_event_t *events, unsigned long event_count)
124 {
125     TS *plugin_data = (TS *) instance;
126     LADSPA_Data *const output = plugin_data->output;
127     LADSPA_Data freq = *(plugin_data->freq);
128     LADSPA_Data vol = *(plugin_data->vol);
129     note_data *data = plugin_data->data;
130     unsigned long pos;
131     unsigned long event_pos;
132     unsigned long note;
133 
134     if (freq < 1.0) {
135 	freq = 440.0f;
136     }
137     if (vol < 0.000001) {
138 	vol = 1.0f;
139     }
140 
141     if (event_count > 0) {
142 	printf("trivial_synth: have %ld events\n", event_count);
143     }
144 
145     for (pos = 0, event_pos = 0; pos < sample_count; pos++) {
146 
147 	while (event_pos < event_count
148 	       && pos == events[event_pos].time.tick) {
149 
150 	    printf("trivial_synth: event type %d\n", events[event_pos].type);
151 
152 	    if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
153 		data[events[event_pos].data.note.note].amp =
154 		    events[event_pos].data.note.velocity / 512.0f;
155 		data[events[event_pos].data.note.note].
156 		    active = events[event_pos].data.note.velocity > 0;
157 		data[events[event_pos].data.note.note].
158 		    phase = 0.0;
159 	    } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF) {
160 		data[events[event_pos].data.note.note].
161 		    active = 0;
162 	    }
163 	    event_pos++;
164 	}
165 
166 	/* this is a crazy way to run a synths inner loop, I've
167 	   just done it this way so its really obvious whats going on */
168 	output[pos] = 0.0f;
169 	for (note = 0; note < MIDI_NOTES; note++) {
170 	    if (data[note].active) {
171 		output[pos] += sin(data[note].phase) * data[note].amp * vol;
172 		data[note].phase += plugin_data->omega[note] * freq;
173 		if (data[note].phase > M_PI * 2.0) {
174 		    data[note].phase -= M_PI * 2.0;
175 		}
176 	    }
177 	}
178     }
179 }
180 
getControllerTS(LADSPA_Handle instance,unsigned long port)181 int getControllerTS(LADSPA_Handle instance, unsigned long port)
182 {
183     switch (port) {
184     case TS_VOLUME:
185 	return DSSI_CC(7);
186     case TS_FREQ:
187 	return DSSI_CC(9);
188     }
189 
190     return -1;
191 }
192 
193 #ifdef __GNUC__
init()194 __attribute__((constructor)) void init()
195 #else
196 void _init()
197 #endif
198 {
199     char **port_names;
200     LADSPA_PortDescriptor *port_descriptors;
201     LADSPA_PortRangeHint *port_range_hints;
202 
203     tsLDescriptor =
204 	(LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
205     if (tsLDescriptor) {
206 	tsLDescriptor->UniqueID = 23;
207 	tsLDescriptor->Label = "TS";
208 	tsLDescriptor->Properties = 0;
209 	tsLDescriptor->Name = "Trivial synth";
210 	tsLDescriptor->Maker = "Steve Harris <steve@plugin.org.uk>";
211 	tsLDescriptor->Copyright = "Public Domain";
212 	tsLDescriptor->PortCount = 3;
213 
214 	port_descriptors = (LADSPA_PortDescriptor *)
215 				calloc(tsLDescriptor->PortCount, sizeof
216 						(LADSPA_PortDescriptor));
217 	tsLDescriptor->PortDescriptors =
218 	    (const LADSPA_PortDescriptor *) port_descriptors;
219 
220 	port_range_hints = (LADSPA_PortRangeHint *)
221 				calloc(tsLDescriptor->PortCount, sizeof
222 						(LADSPA_PortRangeHint));
223 	tsLDescriptor->PortRangeHints =
224 	    (const LADSPA_PortRangeHint *) port_range_hints;
225 
226 	port_names = (char **) calloc(tsLDescriptor->PortCount, sizeof(char *));
227 	tsLDescriptor->PortNames = (const char **) port_names;
228 
229 	/* Parameters for Output */
230 	port_descriptors[TS_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
231 	port_names[TS_OUTPUT] = "Output";
232 	port_range_hints[TS_OUTPUT].HintDescriptor = 0;
233 
234 	/* Parameters for Freq */
235 	port_descriptors[TS_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
236 	port_names[TS_FREQ] = "Tuning frequency";
237 	port_range_hints[TS_FREQ].HintDescriptor = LADSPA_HINT_DEFAULT_440 |
238 			LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
239 	port_range_hints[TS_FREQ].LowerBound = 420;
240 	port_range_hints[TS_FREQ].UpperBound = 460;
241 
242 	/* Parameters for Volume */
243 	port_descriptors[TS_VOLUME] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
244 	port_names[TS_VOLUME] = "Volume";
245 	port_range_hints[TS_VOLUME].HintDescriptor =
246 			LADSPA_HINT_DEFAULT_MAXIMUM |
247 			LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
248 	port_range_hints[TS_VOLUME].LowerBound = 0.0;
249 	port_range_hints[TS_VOLUME].UpperBound = 1.0;
250 
251 	tsLDescriptor->activate = activateTS;
252 	tsLDescriptor->cleanup = cleanupTS;
253 	tsLDescriptor->connect_port = connectPortTS;
254 	tsLDescriptor->deactivate = NULL;
255 	tsLDescriptor->instantiate = instantiateTS;
256 	tsLDescriptor->run = runTSWrapper;
257 	tsLDescriptor->run_adding = NULL;
258 	tsLDescriptor->set_run_adding_gain = NULL;
259     }
260 
261     tsDDescriptor = (DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
262     if (tsDDescriptor) {
263 	tsDDescriptor->DSSI_API_Version = 1;
264 	tsDDescriptor->LADSPA_Plugin = tsLDescriptor;
265 	tsDDescriptor->configure = NULL;
266 	tsDDescriptor->get_program = NULL;
267 	tsDDescriptor->get_midi_controller_for_port = getControllerTS;
268 	tsDDescriptor->select_program = NULL;
269 	tsDDescriptor->run_synth = runTS;
270 	tsDDescriptor->run_synth_adding = NULL;
271 	tsDDescriptor->run_multiple_synths = NULL;
272 	tsDDescriptor->run_multiple_synths_adding = NULL;
273     }
274 }
275 
276 #ifdef __GNUC__
fini()277 __attribute__((destructor)) void fini()
278 #else
279 void _fini()
280 #endif
281 {
282     if (tsLDescriptor) {
283 	free((LADSPA_PortDescriptor *) tsLDescriptor->PortDescriptors);
284 	free((char **) tsLDescriptor->PortNames);
285 	free((LADSPA_PortRangeHint *) tsLDescriptor->PortRangeHints);
286 	free(tsLDescriptor);
287     }
288     if (tsDDescriptor) {
289 	free(tsDDescriptor);
290     }
291 }
292