1 #ifdef _HAVE_PORTAUDIO_
2 /*
3  * portaudiobackend.c
4  * PortAudio backend.
5  *
6  * for Denemo, a gtk+ frontend to GNU Lilypond
7  * Copyright (C) 2011  Dominic Sacré
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  */
14 #include <glib/gstdio.h>
15 #include "audio/portaudiobackend.h"
16 #include "audio/portaudioutil.h"
17 #ifdef _HAVE_RUBBERBAND_
18     #include <rubberband/rubberband-c.h>
19 #endif
20 #include "audio/midi.h"
21 #include "audio/fluid.h"
22 #include "audio/audiointerface.h"
23 
24 #include <portaudio.h>
25 #include <glib.h>
26 #include <string.h>
27 #include "export/audiofile.h"
28 #include "core/utils.h"
29 
30 static PaStream *stream;
31 static unsigned long sample_rate;
32 
33 static unsigned long playback_frame = 0;
34 
35 static gboolean reset_audio = FALSE;
36 
37 static gint ready = FALSE;
38 
39 static double slowdown = 1.0; //2.0 = twice as long ie half speed.
40 static gboolean rubberband_active = FALSE;
41 
42 #ifdef _HAVE_RUBBERBAND_
43 static RubberBandState rubberband;
rubberband_init(DenemoPrefs * config)44 static gint rubberband_init(DenemoPrefs *config) {
45     rubberband = rubberband_new(sample_rate, 2 /* channels */, RubberBandOptionProcessRealTime | RubberBandOptionStretchPrecise,
46     slowdown, 1.0);
47     //rubberband_set_debug_level(rubberband, 3);
48     return 0;
49 }
set_playback_speed(double speed)50 void set_playback_speed (double speed) {
51     if(rubberband==NULL)
52         rubberband_init(&Denemo.prefs);
53     Denemo.project->movement->end_time /= slowdown;
54     Denemo.project->movement->start_time /= slowdown;
55     if(speed>1.01) {
56         slowdown = speed;
57         rubberband_active = TRUE;
58     }
59     else
60     {
61         slowdown = 1.0;
62         rubberband_active = FALSE;
63     }
64     rubberband_set_time_ratio(rubberband, slowdown);
65     Denemo.project->movement->end_time *= slowdown;
66     Denemo.project->movement->start_time *= slowdown;
67 }
68 
get_playback_speed(void)69 gdouble get_playback_speed (void)
70 {
71     return slowdown;
72 }
73 #endif
74 
75 
76 static double
nframes_to_seconds(unsigned long nframes)77 nframes_to_seconds (unsigned long nframes)
78 {
79   return nframes / (double) sample_rate;
80 }
81 
82 static unsigned long
seconds_to_nframes(double seconds)83 seconds_to_nframes (double seconds)
84 {
85   return (unsigned long) (sample_rate * seconds);
86 }
87 
88 #define MAX_MESSAGE_LENGTH (255)        //Allow single sysex blocks, ie 0xF0, length, data...0xF7  where length is one byte.
89 
record_audio(float ** buffers,unsigned long frames_per_buffer)90 static void record_audio(float ** buffers, unsigned long frames_per_buffer){
91   // Recording audio out - only one channel is saved at the moment, so source audio (which is dumped in the second channel) is not recorded.
92   if (Denemo.prefs.maxrecordingtime <= 0)
93     return;
94   static FILE *fp = NULL;
95   if (Denemo.project && Denemo.project->audio_recording)
96     {
97       static guint recorded_frames;
98       if (fp == NULL)
99         {
100           const gchar *filename = recorded_audio_filename ();
101           fp = fopen (filename, "wb");
102           recorded_frames = 0;
103           if (fp == NULL)
104             g_warning ("Could not open denemo-output");
105           else
106             g_info ("Opened output file %s", filename);
107         }
108       if (fp)
109         {
110           if (recorded_frames / 44100 < Denemo.prefs.maxrecordingtime)
111             {
112               fwrite (buffers[0], sizeof (float), frames_per_buffer, fp);
113               recorded_frames += frames_per_buffer;
114             }
115           else
116             {               //only warn once, don't spew out warnings...
117               if (recorded_frames < G_MAXINT)
118                 {
119                   recorded_frames = G_MAXINT;
120                   g_warning ("Recording length exceeded preference (%d seconds); use the Change Preferences dialog to alter this", Denemo.prefs.maxrecordingtime);
121                 }
122             }
123         }
124     }
125   else
126     {
127       if (fp)
128         {
129           fclose (fp);
130           fp = NULL;
131           g_message ("File closed samples are raw data, Little Endian (? or architecture dependent), mono");
132         }
133     }
134 }
135 
136 static int
stream_callback(const void * input_buffer,void * output_buffer,unsigned long frames_per_buffer,const PaStreamCallbackTimeInfo * time_info,PaStreamCallbackFlags status_flags,void * user_data)137 stream_callback (const void *input_buffer, void *output_buffer, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo * time_info, PaStreamCallbackFlags status_flags, void *user_data)
138 {
139   float **buffers = (float **) output_buffer;
140 #ifdef _HAVE_RUBBERBAND_
141   static gboolean initialized = FALSE;
142   if (!initialized) {
143       rubberband_set_max_process_size(rubberband, frames_per_buffer);
144       initialized = TRUE;
145   }
146 #endif
147 
148   size_t i;
149   for (i = 0; i < 2; ++i)
150     {
151       memset (buffers[i], 0, frames_per_buffer * sizeof (float));
152     }
153 
154   if (!ready)
155     return paContinue;
156 
157 #ifdef _HAVE_FLUIDSYNTH_
158   if (reset_audio)
159     {
160       fluidsynth_all_notes_off ();
161       reset_synth_channels ();
162       reset_audio = FALSE;
163       return paContinue;
164     }
165 
166   unsigned char event_data[MAX_MESSAGE_LENGTH]; //needs to be long enough for variable length messages...
167   size_t event_length = MAX_MESSAGE_LENGTH;
168   double event_time;
169 
170   double until_time = nframes_to_seconds (playback_frame + frames_per_buffer);
171 #ifdef _HAVE_RUBBERBAND_
172   gint available = rubberband_available(rubberband);
173 if((!rubberband_active) || (available < (gint)frames_per_buffer)) {
174 #endif
175 
176   while (read_event_from_queue (AUDIO_BACKEND, event_data, &event_length, &event_time, until_time/slowdown))
177     {//g_debug("%d ", event_data[1] );
178       fluidsynth_feed_midi (event_data, event_length);  //in fluid.c note fluidsynth api ues fluid_synth_xxx these naming conventions are a bit too similar
179     }
180 
181   fluidsynth_render_audio (frames_per_buffer, buffers[0], buffers[1]);  //in fluid.c calls fluid_synth_write_float()
182 
183 // Now get any audio to mix - dump it in the left hand channel for now
184   event_length = frames_per_buffer;
185   read_event_from_mixer_queue (AUDIO_BACKEND, (void *) buffers[1], &event_length);
186 
187 #ifdef _HAVE_RUBBERBAND_
188   }
189   //if there is stuff available use it and give buffers[] to rubber band to process
190   if(rubberband_active)
191       {
192       if(available < (gint)frames_per_buffer)
193           rubberband_process(rubberband, (const float * const*)buffers, frames_per_buffer, 0);
194       available = rubberband_available(rubberband);
195       if(available >= (gint)frames_per_buffer)
196           {
197               rubberband_retrieve(rubberband, buffers, frames_per_buffer);//re-use buffers[] as they are available...
198               write_samples_to_rubberband_queue (AUDIO_BACKEND, buffers[0], frames_per_buffer);
199               write_samples_to_rubberband_queue (AUDIO_BACKEND,  buffers[1], frames_per_buffer);
200               available -= frames_per_buffer;
201           }
202       event_length = frames_per_buffer;
203       read_event_from_rubberband_queue (AUDIO_BACKEND, (unsigned char *) buffers[0], &event_length);
204       event_length = frames_per_buffer;
205       read_event_from_rubberband_queue (AUDIO_BACKEND, (unsigned char *) buffers[1],  &event_length);
206       }
207 #endif //_HAVE_RUBBERBAND_
208 
209   if (until_time < get_playuntil ())
210     {
211 #endif //_HAVE_FLUIDSYNTH_
212       playback_frame += frames_per_buffer;
213       update_playback_time (TIMEBASE_PRIO_AUDIO, nframes_to_seconds (playback_frame));
214 #ifdef _HAVE_FLUIDSYNTH_
215     }
216 #endif //_HAVE_FLUIDSYNTH_
217 
218   // This is probably a bad idea to do heavy work in an audio callback
219   record_audio(buffers, frames_per_buffer);
220   return paContinue;
221 }
222 
223 static int
actual_portaudio_initialize(DenemoPrefs * config)224 actual_portaudio_initialize (DenemoPrefs * config)
225 {
226   sample_rate = config->portaudio_sample_rate;
227 
228 #ifdef _HAVE_FLUIDSYNTH_
229   g_message ("Initializing Fluidsynth");
230   if (fluidsynth_init (config, sample_rate))
231     {
232       g_warning ("Initializing Fluidsynth FAILED!");
233       return -1;
234     }
235 #endif
236 #ifdef _HAVE_RUBBERBAND_
237   g_message ("Initializing Rubberband");
238  if (rubberband_init (config))
239     {
240       g_warning ("Initializing Rubberband FAILED!");
241       return -1;
242     }
243 #endif
244   g_unlink (recorded_audio_filename ());
245 
246   g_message ("Initializing PortAudio backend");
247   g_info("PortAudio version: %s", Pa_GetVersionText());
248 
249   PaStreamParameters output_parameters;
250   PaError err;
251 
252   err = Pa_Initialize ();
253   if (err != paNoError)
254     {
255       g_warning ("Initializing PortAudio failed");
256       return -1;
257     }
258 
259   output_parameters.device = get_portaudio_device_index (config->portaudio_device->str);
260 
261   if (output_parameters.device == paNoDevice)
262     {
263       output_parameters.device =   get_portaudio_device_index ("default");
264        if (output_parameters.device == paNoDevice)
265         {
266             g_warning("No PortAudio device %s and no default either.", config->portaudio_device->str);
267             return -1;
268         }
269     }
270 
271   PaDeviceInfo const *info = Pa_GetDeviceInfo (output_parameters.device);
272 
273   if (!info)
274     {
275       g_warning ("Invalid device '%s'", config->portaudio_device->str);
276       return -1;
277     }
278 
279   char const *api_name = Pa_GetHostApiInfo (info->hostApi)->name;
280   g_message ("Opening output device '%s: %s'", api_name, info->name);
281 
282   output_parameters.channelCount = 2;
283   output_parameters.sampleFormat = paFloat32 | paNonInterleaved;
284   output_parameters.suggestedLatency = Pa_GetDeviceInfo (output_parameters.device)->defaultLowOutputLatency;
285   output_parameters.hostApiSpecificStreamInfo = NULL;
286   err = Pa_OpenStream (&stream, NULL, &output_parameters, config->portaudio_sample_rate, config->portaudio_period_size, paNoFlag /* make this a pref??? paClipOff */ , stream_callback, NULL);
287   if (err != paNoError)
288     {
289       g_warning ("Couldn't open output stream");
290       return -1;
291     }
292   err = Pa_StartStream (stream);
293   if (err != paNoError)
294     {
295       g_warning ("Couldn't start output stream");
296       return -1;
297     }
298 
299   return 0;
300 }
301 
302 static int
ready_now()303 ready_now ()
304 {
305   ready = TRUE;
306   return FALSE;
307 }
308 
309 static int
portaudio_initialize(DenemoPrefs * config)310 portaudio_initialize (DenemoPrefs * config)
311 {
312   g_idle_add ((GSourceFunc) ready_now, NULL);
313   return actual_portaudio_initialize (config);
314 }
315 
316 static int
portaudio_destroy()317 portaudio_destroy ()
318 {
319   g_message ("Destroying PortAudio backend");
320   ready = FALSE;
321   PaError err;
322 
323   err = Pa_CloseStream (stream);
324   if (err != paNoError)
325     {
326       g_warning ("Closing stream failed: %d, %s", err, Pa_GetErrorText (err));
327       return -1;
328     }
329 
330   Pa_Terminate ();
331 
332 #ifdef _HAVE_FLUIDSYNTH_
333   fluidsynth_shutdown ();
334 #endif
335 
336   return 0;
337 }
338 
339 
340 static int
portaudio_reconfigure(DenemoPrefs * config)341 portaudio_reconfigure (DenemoPrefs * config)
342 {
343   portaudio_destroy ();
344   return portaudio_initialize (config);
345 }
346 
347 
348 static int
portaudio_start_playing()349 portaudio_start_playing ()
350 {
351   playback_frame = seconds_to_nframes (get_playback_time ());
352   return 0;
353 }
354 
355 
356 static int
portaudio_stop_playing()357 portaudio_stop_playing ()
358 {
359   reset_audio = TRUE;
360   return 0;
361 }
362 
363 
364 static int
portaudio_panic()365 portaudio_panic ()
366 {
367   reset_audio = TRUE;
368   return 0;
369 }
370 
371 
372 backend_t portaudio_backend = {
373   portaudio_initialize,
374   portaudio_destroy,
375   portaudio_reconfigure,
376   portaudio_start_playing,
377   portaudio_stop_playing,
378   portaudio_panic,
379 };
380 #endif //_HAVE_PORTAUDIO_
381