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