1 /*
2  * This is a C99 program that outlines different usage examples for fluid_synth_process()
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <fluidsynth.h>
8 
main()9 int main()
10 {
11     // any arbitrary number of audio samples to render during on call of fluid_synth_process()
12     enum { SAMPLES = 512 };
13 
14     // ...creation of synth omitted...
15 
16     // USECASE1: render all dry audio channels + reverb and chorus to one stereo channel
17     {
18         // planar sample buffers that received synthesized (monophonic) audio
19         float left[SAMPLES], right[SAMPLES];
20 
21         // array of buffers used to setup channel mapping
22         float *dry[1 * 2], *fx[1 * 2];
23 
24         // first make sure to zero out the sample buffers every time before calling fluid_synth_process()
25         memset(left, 0, sizeof(left));
26         memset(right, 0, sizeof(right));
27 
28         // setup channel mapping for a single stereo channel to which to render all dry audio to
29         dry[0] = left;
30         dry[1] = right;
31 
32         // Setup channel mapping for a single stereo channel to which to render effects to.
33         // Just using the same sample buffers as for dry audio is fine here, as it will cause the effects to be mixed with dry output.
34         // Note: reverb and chorus together make up two stereo channels. Setting up only one stereo channel is sufficient
35         // as the channels wraps around (i.e. chorus will be mixed with reverb channel).
36         fx[0] = left;
37         fx[1] = right;
38 
39         int err = fluid_synth_process(synth, SAMPLES, 2, fx, 2, dry);
40 
41         if(err == FLUID_FAILED)
42         {
43             puts("oops");
44         }
45 
46 
47         // USECASE2: only render dry audio and discard effects
48         // same as above, but call fluid_synth_process() like:
49         int err = fluid_synth_process(synth, SAMPLES, 0, NULL, 2, dry);
50 
51         if(err == FLUID_FAILED)
52         {
53             puts("oops");
54         }
55     }
56 
57 
58     // USECASE3: render audio and discard all samples
59     {
60         int err = fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL);
61 
62         if(err == FLUID_FAILED)
63         {
64             puts("oops");
65         }
66     }
67 
68 
69     // USECASE4: multi-channel rendering, i.e. render all audio and effects channels to dedicated audio buffers
70     // ofc it‘s not a good idea to allocate all the arrays on the stack
71     {
72         // lookup number of audio and effect (stereo-)channels of the synth
73         // see "synth.audio-channels", "synth.effects-channels" and "synth.effects-groups" settings respectively
74         int n_aud_chan = fluid_synth_count_audio_channels(synth);
75 
76         // by default there are two effects stereo channels (reverb and chorus) ...
77         int n_fx_chan = fluid_synth_count_effects_channels(synth);
78 
79         // ... for each effects unit. Each unit takes care of the effects of one MIDI channel.
80         // If there are less units than channels, it wraps around and one unit may render effects of multiple
81         // MIDI channels.
82         n_fx_chan *= fluid_synth_count_effects_groups();
83 
84         // for simplicity, allocate one single sample pool
85         float samp_buf[SAMPLES * (n_aud_chan + n_fx_chan) * 2];
86 
87         // array of buffers used to setup channel mapping
88         float *dry[n_aud_chan * 2], *fx[n_fx_chan * 2];
89 
90         // setup buffers to mix dry stereo audio to
91         // buffers are alternating left and right for each n_aud_chan,
92         // please review documentation of fluid_synth_process()
93         for(int i = 0; i < n_aud_chan * 2; i++)
94         {
95             dry[i] = &samp_buf[i * SAMPLES];
96         }
97 
98         // setup buffers to mix effects stereo audio to
99         // similar channel layout as above, revie fluid_synth_process()
100         for(int i = 0; i < n_fx_chan * 2; i++)
101         {
102             fx[i] = &samp_buf[n_aud_chan * 2 * SAMPLES + i * SAMPLES];
103         }
104 
105         // dont forget to zero sample buffer(s) before each rendering
106         memset(samp_buf, 0, sizeof(samp_buf));
107 
108         int err = fluid_synth_process(synth, SAMPLES, n_fx_chan * 2, fx, n_aud_chan * 2, dry);
109 
110         if(err == FLUID_FAILED)
111         {
112             puts("oops");
113         }
114     }
115 
116     return 0;
117 }
118