1 /* FluidSynth Arpeggio - Sequencer API example
2  *
3  * This code is in the public domain.
4  *
5  * To compile:
6  *   gcc -o fluidsynth_arpeggio -lfluidsynth fluidsynth_arpeggio.c
7  *
8  * To run:
9  *   fluidsynth_arpeggio soundfont [steps [duration]]
10  *
11  * [Pedro Lopez-Cabanillas <plcl@users.sf.net>]
12  */
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <fluidsynth.h>
17 
18 fluid_synth_t *synth;
19 fluid_audio_driver_t *audiodriver;
20 fluid_sequencer_t *sequencer;
21 short synth_destination, client_destination;
22 unsigned int time_marker;
23 /* duration of the pattern in ticks. */
24 unsigned int duration = 1440;
25 /* notes of the arpeggio */
26 unsigned int notes[] = { 60, 64, 67, 72, 76, 79, 84, 79, 76, 72, 67, 64 };
27 /* number of notes in one pattern */
28 unsigned int pattern_size;
29 /* prototype */
30 void
31 sequencer_callback(unsigned int time, fluid_event_t *event,
32                    fluid_sequencer_t *seq, void *data);
33 
34 /* schedule a note on message */
35 void
schedule_noteon(int chan,short key,unsigned int ticks)36 schedule_noteon(int chan, short key, unsigned int ticks)
37 {
38     fluid_event_t *ev = new_fluid_event();
39     fluid_event_set_source(ev, -1);
40     fluid_event_set_dest(ev, synth_destination);
41     fluid_event_noteon(ev, chan, key, 127);
42     fluid_sequencer_send_at(sequencer, ev, ticks, 1);
43     delete_fluid_event(ev);
44 }
45 
46 /* schedule a note off message */
47 void
schedule_noteoff(int chan,short key,unsigned int ticks)48 schedule_noteoff(int chan, short key, unsigned int ticks)
49 {
50     fluid_event_t *ev = new_fluid_event();
51     fluid_event_set_source(ev, -1);
52     fluid_event_set_dest(ev, synth_destination);
53     fluid_event_noteoff(ev, chan, key);
54     fluid_sequencer_send_at(sequencer, ev, ticks, 1);
55     delete_fluid_event(ev);
56 }
57 
58 /* schedule a timer event (shall trigger the callback) */
59 void
schedule_timer_event(void)60 schedule_timer_event(void)
61 {
62     fluid_event_t *ev = new_fluid_event();
63     fluid_event_set_source(ev, -1);
64     fluid_event_set_dest(ev, client_destination);
65     fluid_event_timer(ev, NULL);
66     fluid_sequencer_send_at(sequencer, ev, time_marker, 1);
67     delete_fluid_event(ev);
68 }
69 
70 /* schedule the arpeggio's notes */
71 void
schedule_pattern(void)72 schedule_pattern(void)
73 {
74     unsigned int i;
75     int note_time, note_duration;
76     note_time = time_marker;
77     note_duration = duration / pattern_size;
78 
79     for(i = 0; i < pattern_size; ++i)
80     {
81         schedule_noteon(0, notes[i], note_time);
82         note_time += note_duration;
83         schedule_noteoff(0, notes[i], note_time);
84     }
85 
86     time_marker += duration;
87 }
88 
89 void
sequencer_callback(unsigned int time,fluid_event_t * event,fluid_sequencer_t * seq,void * data)90 sequencer_callback(unsigned int time, fluid_event_t *event,
91                    fluid_sequencer_t *seq, void *data)
92 {
93     schedule_timer_event();
94     schedule_pattern();
95 }
96 
97 void
usage(char * prog_name)98 usage(char *prog_name)
99 {
100     printf("Usage: %s soundfont.sf2 [steps [duration]]\n", prog_name);
101     printf("\t(optional) steps: number of pattern notes, from 2 to %d\n",
102            pattern_size);
103     printf("\t(optional) duration: of the pattern in ticks, default %d\n",
104            duration);
105 }
106 
107 int
main(int argc,char * argv[])108 main(int argc, char *argv[])
109 {
110     int n;
111     fluid_settings_t *settings;
112     settings = new_fluid_settings();
113     pattern_size = sizeof(notes) / sizeof(int);
114 
115     if(argc < 2)
116     {
117         usage(argv[0]);
118     }
119     else
120     {
121         /* create the synth, driver and sequencer instances */
122         synth = new_fluid_synth(settings);
123         /* load a SoundFont */
124         n = fluid_synth_sfload(synth, argv[1], 1);
125 
126         if(n != -1)
127         {
128             sequencer = new_fluid_sequencer2(0);
129             /* register the synth with the sequencer */
130             synth_destination = fluid_sequencer_register_fluidsynth(sequencer,
131                                 synth);
132             /* register the client name and callback */
133             client_destination = fluid_sequencer_register_client(sequencer,
134                              "arpeggio", sequencer_callback, NULL);
135             if(argc > 2)
136             {
137                 n = atoi(argv[2]);
138 
139                 if((n > 1) && (n <= (int)pattern_size))
140                 {
141                     pattern_size = n;
142                 }
143             }
144 
145             if(argc > 3)
146             {
147                 n = atoi(argv[3]);
148 
149                 if(n > 0)
150                 {
151                     duration = n;
152                 }
153             }
154 
155             audiodriver = new_fluid_audio_driver(settings, synth);
156 
157             /* get the current time in ticks */
158             time_marker = fluid_sequencer_get_tick(sequencer);
159             /* schedule patterns */
160             schedule_pattern();
161             schedule_timer_event();
162             schedule_pattern();
163             /* wait for user input */
164             printf("press <Enter> to stop\n");
165             n = getchar();
166         }
167 
168         /* clean and exit */
169         delete_fluid_audio_driver(audiodriver);
170         delete_fluid_sequencer(sequencer);
171         delete_fluid_synth(synth);
172     }
173 
174     delete_fluid_settings(settings);
175     return 0;
176 }
177