fluid_pulse.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:8k
源码类别:

midi

开发平台:

C/C++

  1. /* FluidSynth - A Software Synthesizer
  2.  *
  3.  * Copyright (C) 2003  Peter Hanappe and others.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Library General Public License
  7.  * as published by the Free Software Foundation; either version 2 of
  8.  * the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Library General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Library General Public
  16.  * License along with this library; if not, write to the Free
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18.  * 02111-1307, USA
  19.  */
  20. /* fluid_pulse.c
  21.  *
  22.  * Audio driver for PulseAudio.
  23.  *
  24.  */
  25. #include "fluid_synth.h"
  26. #include "fluid_adriver.h"
  27. #include "fluid_settings.h"
  28. #include "config.h"
  29. #include <pulse/simple.h>
  30. #include <pulse/error.h>
  31. /** fluid_pulse_audio_driver_t
  32.  *
  33.  * This structure should not be accessed directly. Use audio port
  34.  * functions instead.
  35.  */
  36. typedef struct {
  37.   fluid_audio_driver_t driver;
  38.   pa_simple *pa_handle;
  39.   fluid_audio_func_t callback;
  40.   void* data;
  41.   int buffer_size;
  42.   fluid_thread_t *thread;
  43.   int cont;
  44. } fluid_pulse_audio_driver_t;
  45. fluid_audio_driver_t* new_fluid_pulse_audio_driver(fluid_settings_t* settings,
  46.    fluid_synth_t* synth);
  47. fluid_audio_driver_t* new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
  48.     fluid_audio_func_t func, void* data);
  49. int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p);
  50. void fluid_pulse_audio_driver_settings(fluid_settings_t* settings);
  51. static void fluid_pulse_audio_run(void* d);
  52. static void fluid_pulse_audio_run2(void* d);
  53. void fluid_pulse_audio_driver_settings(fluid_settings_t* settings)
  54. {
  55.   fluid_settings_register_str(settings, "audio.pulseaudio.server", "default", 0, NULL, NULL);
  56.   fluid_settings_register_str(settings, "audio.pulseaudio.device", "default", 0, NULL, NULL);
  57.   fluid_settings_register_str(settings, "audio.pulseaudio.media-role", "music", 0, NULL, NULL);
  58.   fluid_settings_register_int(settings, "audio.pulseaudio.adjust-latency", 1, 0, 1,
  59.                               FLUID_HINT_TOGGLED, NULL, NULL);
  60. }
  61. fluid_audio_driver_t*
  62. new_fluid_pulse_audio_driver(fluid_settings_t* settings,
  63.     fluid_synth_t* synth)
  64. {
  65.   return new_fluid_pulse_audio_driver2(settings, NULL, synth);
  66. }
  67. fluid_audio_driver_t*
  68. new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
  69.      fluid_audio_func_t func, void* data)
  70. {
  71.   fluid_pulse_audio_driver_t* dev;
  72.   pa_sample_spec samplespec;
  73.   pa_buffer_attr bufattr;
  74.   double sample_rate;
  75.   int period_size, period_bytes, adjust_latency;
  76.   char *server = NULL;
  77.   char *device = NULL;
  78.   char *media_role = NULL;
  79.   int realtime_prio = 0;
  80.   int err;
  81.   dev = FLUID_NEW(fluid_pulse_audio_driver_t);
  82.   if (dev == NULL) {
  83.     FLUID_LOG(FLUID_ERR, "Out of memory");
  84.     return NULL;
  85.   }
  86.   FLUID_MEMSET(dev, 0, sizeof(fluid_pulse_audio_driver_t));
  87. //  fluid_settings_getint(settings, "audio.periods", &periods);
  88.   fluid_settings_getint(settings, "audio.period-size", &period_size);
  89.   fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
  90.   fluid_settings_dupstr(settings, "audio.pulseaudio.server", &server);  /* ++ alloc server string */
  91.   fluid_settings_dupstr(settings, "audio.pulseaudio.device", &device);  /* ++ alloc device string */
  92.   fluid_settings_dupstr(settings, "audio.pulseaudio.media-role", &media_role);  /* ++ alloc media-role string */
  93.   fluid_settings_getint(settings, "audio.realtime-prio", &realtime_prio);
  94.   fluid_settings_getint(settings, "audio.pulseaudio.adjust-latency", &adjust_latency);
  95.   if (media_role != NULL) {
  96.     if (strcmp(media_role, "") != 0) {
  97.       g_setenv("PULSE_PROP_media.role", media_role, TRUE);
  98.     }
  99.     FLUID_FREE (media_role);      /* -- free media_role string */
  100.   }
  101.   if (server && strcmp (server, "default") == 0)
  102.   {
  103.     FLUID_FREE (server);        /* -- free server string */
  104.     server = NULL;
  105.   }
  106.   if (device && strcmp (device, "default") == 0)
  107.   {
  108.     FLUID_FREE (device);        /* -- free device string */
  109.     device = NULL;
  110.   }
  111.   dev->data = data;
  112.   dev->callback = func;
  113.   dev->cont = 1;
  114.   dev->buffer_size = period_size;
  115.   samplespec.format = PA_SAMPLE_FLOAT32NE;
  116.   samplespec.channels = 2;
  117.   samplespec.rate = sample_rate;
  118.   period_bytes = period_size * sizeof (float) * 2;
  119.   bufattr.maxlength = adjust_latency ? -1 : period_bytes;
  120.   bufattr.tlength = period_bytes;
  121.   bufattr.minreq = -1;
  122.   bufattr.prebuf = -1;    /* Just initialize to same value as tlength */
  123.   bufattr.fragsize = -1;  /* Not used */
  124.   dev->pa_handle = pa_simple_new (server, "FluidSynth", PA_STREAM_PLAYBACK,
  125.   device, "FluidSynth output", &samplespec,
  126.   NULL, /* pa_channel_map */
  127.   &bufattr,
  128.   &err);
  129.   if (!dev->pa_handle)
  130.   {
  131.     FLUID_LOG(FLUID_ERR, "Failed to create PulseAudio connection");
  132.     goto error_recovery;
  133.   }
  134.   FLUID_LOG(FLUID_INFO, "Using PulseAudio driver");
  135.   /* Create the audio thread */
  136.   dev->thread = new_fluid_thread (func ? fluid_pulse_audio_run2 : fluid_pulse_audio_run,
  137.                                   dev, realtime_prio, FALSE);
  138.   if (!dev->thread)
  139.     goto error_recovery;
  140.   if (server) FLUID_FREE (server);      /* -- free server string */
  141.   if (device) FLUID_FREE (device);      /* -- free device string */
  142.   return (fluid_audio_driver_t*) dev;
  143.  error_recovery:
  144.   if (server) FLUID_FREE (server);      /* -- free server string */
  145.   if (device) FLUID_FREE (device);      /* -- free device string */
  146.   delete_fluid_pulse_audio_driver((fluid_audio_driver_t*) dev);
  147.   return NULL;
  148. }
  149. int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p)
  150. {
  151.   fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) p;
  152.   if (dev == NULL) {
  153.     return FLUID_OK;
  154.   }
  155.   dev->cont = 0;
  156.   if (dev->thread)
  157.     fluid_thread_join (dev->thread);
  158.   if (dev->pa_handle)
  159.     pa_simple_free(dev->pa_handle);
  160.   FLUID_FREE(dev);
  161.   return FLUID_OK;
  162. }
  163. /* Thread without audio callback, more efficient */
  164. static void
  165. fluid_pulse_audio_run(void* d)
  166. {
  167.   fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
  168.   float *buf;
  169.   int buffer_size;
  170.   int err;
  171.   buffer_size = dev->buffer_size;
  172.   /* FIXME - Probably shouldn't alloc in run() */
  173.   buf = FLUID_ARRAY(float, buffer_size * 2);
  174.   if (buf == NULL)
  175.   {
  176.     FLUID_LOG(FLUID_ERR, "Out of memory.");
  177.     return;
  178.   }
  179.   while (dev->cont)
  180.   {
  181.     fluid_synth_write_float(dev->data, buffer_size, buf, 0, 2, buf, 1, 2);
  182.     if (pa_simple_write (dev->pa_handle, buf,
  183.  buffer_size * sizeof (float) * 2, &err) < 0)
  184.     {
  185.       FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection.");
  186.       break;
  187.     }
  188.   } /* while (dev->cont) */
  189.   FLUID_FREE(buf);
  190. }
  191. static void
  192. fluid_pulse_audio_run2(void* d)
  193. {
  194.   fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
  195.   fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
  196.   float *left, *right, *buf;
  197.   float* handle[2];
  198.   int buffer_size;
  199.   int err;
  200.   int i;
  201.   buffer_size = dev->buffer_size;
  202.   /* FIXME - Probably shouldn't alloc in run() */
  203.   left = FLUID_ARRAY(float, buffer_size);
  204.   right = FLUID_ARRAY(float, buffer_size);
  205.   buf = FLUID_ARRAY(float, buffer_size * 2);
  206.   if (left == NULL || right == NULL || buf == NULL)
  207.   {
  208.     FLUID_LOG(FLUID_ERR, "Out of memory.");
  209.     return;
  210.   }
  211.   handle[0] = left;
  212.   handle[1] = right;
  213.   while (dev->cont)
  214.   {
  215.     (*dev->callback)(synth, buffer_size, 0, NULL, 2, handle);
  216.     /* Interleave the floating point data */
  217.     for (i = 0; i < buffer_size; i++)
  218.     {
  219.       buf[i * 2] = left[i];
  220.       buf[i * 2 + 1] = right[i];
  221.     }
  222.     if (pa_simple_write (dev->pa_handle, buf,
  223.  buffer_size * sizeof (float) * 2, &err) < 0)
  224.     {
  225.       FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection.");
  226.       break;
  227.     }
  228.   } /* while (dev->cont) */
  229.   FLUID_FREE(left);
  230.   FLUID_FREE(right);
  231.   FLUID_FREE(buf);
  232. }