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