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

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_portaudio.c
  21.  *
  22.  * Drivers for the PortAudio API : www.portaudio.com
  23.  * Implementation files for PortAudio on each platform have to be added
  24.  *
  25.  * Stephane Letz  (letz@grame.fr)  Grame
  26.  * 12/20/01 Adapdation for new audio drivers
  27.  *
  28.  * Josh Green <jgreen@users.sourceforge.net>
  29.  * 2009-01-28 Overhauled for PortAudio 19 API and current FluidSynth API (was broken)
  30.  */
  31. #include "fluid_synth.h"
  32. #include "fluid_sys.h"
  33. #include "fluid_settings.h"
  34. #include "fluid_adriver.h"
  35. #if PORTAUDIO_SUPPORT
  36. #include <fcntl.h>
  37. #include <unistd.h>
  38. #include <errno.h>
  39. #include <portaudio.h>
  40. /** fluid_portaudio_driver_t
  41.  *
  42.  * This structure should not be accessed directly. Use audio port
  43.  * functions instead.
  44.  */
  45. typedef struct
  46. {
  47.   fluid_audio_driver_t driver;
  48.   fluid_synth_t *synth;
  49.   fluid_audio_callback_t read;
  50.   PaStream *stream;
  51. } fluid_portaudio_driver_t;
  52. static int
  53. fluid_portaudio_run (const void *input, void *output, unsigned long frameCount,
  54.                      const PaStreamCallbackTimeInfo* timeInfo,
  55.                      PaStreamCallbackFlags statusFlags, void *userData);
  56. int delete_fluid_portaudio_driver (fluid_audio_driver_t *p);
  57. #define PORTAUDIO_DEFAULT_DEVICE "PortAudio Default"
  58. void
  59. fluid_portaudio_driver_settings (fluid_settings_t *settings)
  60. {
  61.   const PaDeviceInfo *deviceInfo;
  62.   int numDevices;
  63.   PaError err;
  64.   int i;
  65.   fluid_settings_register_str (settings, "audio.portaudio.device", PORTAUDIO_DEFAULT_DEVICE, 0, NULL, NULL);
  66.   fluid_settings_add_option (settings, "audio.portaudio.device", PORTAUDIO_DEFAULT_DEVICE);
  67.   err = Pa_Initialize();
  68.   if (err != paNoError)
  69.   {
  70.     FLUID_LOG (FLUID_ERR, "Error initializing PortAudio driver: %s",
  71.                Pa_GetErrorText (err));
  72.     return;
  73.   }
  74.   numDevices = Pa_GetDeviceCount();
  75.   if (numDevices < 0)
  76.   {
  77.     FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
  78.     return;
  79.   }
  80.   for (i = 0; i < numDevices; i++)
  81.   {
  82.     deviceInfo = Pa_GetDeviceInfo (i);
  83.     if ( deviceInfo->maxOutputChannels >= 2 )
  84.       fluid_settings_add_option (settings, "audio.portaudio.device",
  85.                                  deviceInfo->name);
  86.   }
  87.   /* done with PortAudio for now, may get reopened later */
  88.   err = Pa_Terminate();
  89.   if (err != paNoError)
  90.     printf ("PortAudio termination error: %sn", Pa_GetErrorText (err) );
  91. }
  92. fluid_audio_driver_t *
  93. new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
  94. {
  95.   fluid_portaudio_driver_t *dev = NULL;
  96.   PaStreamParameters outputParams;
  97.   char *device = NULL;
  98.   double sample_rate;
  99.   int period_size;
  100.   PaError err;
  101.   dev = FLUID_NEW (fluid_portaudio_driver_t);
  102.   if (dev == NULL)
  103.   {
  104.     FLUID_LOG (FLUID_ERR, "Out of memory");
  105.     return NULL;
  106.   }
  107.   err = Pa_Initialize ();
  108.   if (err != paNoError)
  109.   {
  110.     FLUID_LOG (FLUID_ERR, "Error initializing PortAudio driver: %s",
  111.                Pa_GetErrorText (err));
  112.     FLUID_FREE (dev);
  113.     return NULL;
  114.   }
  115.   FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t));
  116.   dev->synth = synth;
  117.   fluid_settings_getint (settings, "audio.period-size", &period_size);
  118.   fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate);
  119.   fluid_settings_dupstr(settings, "audio.portaudio.device", &device);   /* ++ alloc device name */
  120.   bzero (&outputParams, sizeof (outputParams));
  121.   outputParams.channelCount = 2;
  122.   outputParams.suggestedLatency = (PaTime)period_size / sample_rate;
  123.   /* Locate the device if specified */
  124.   if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 0)
  125.   {
  126.     const PaDeviceInfo *deviceInfo;
  127.     int numDevices;
  128.     int i;
  129.     numDevices = Pa_GetDeviceCount ();
  130.     if (numDevices < 0)
  131.     {
  132.       FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
  133.       goto error_recovery;
  134.     }
  135.     for (i = 0; i < numDevices; i++)
  136.     {
  137.       deviceInfo = Pa_GetDeviceInfo (i);
  138.       if (strcmp (device, deviceInfo->name) == 0)
  139.       {
  140.         outputParams.device = i;
  141.         break;
  142.       }
  143.     }
  144.     if (i == numDevices)
  145.     {
  146.       FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device);
  147.       goto error_recovery;
  148.     }
  149.   }
  150.   else outputParams.device = Pa_GetDefaultOutputDevice();
  151.   if (fluid_settings_str_equal (settings, "audio.sample-format", "16bits"))
  152.   {
  153.     outputParams.sampleFormat = paInt16;
  154.     dev->read = fluid_synth_write_s16;
  155.   }
  156.   else if (fluid_settings_str_equal (settings, "audio.sample-format", "float"))
  157.   {
  158.     outputParams.sampleFormat = paFloat32;
  159.     dev->read = fluid_synth_write_float;
  160.   }
  161.   else
  162.   {
  163.     FLUID_LOG (FLUID_ERR, "Unknown sample format");
  164.     goto error_recovery;
  165.   }
  166.   /* PortAudio section */
  167.   /* Open an audio I/O stream. */
  168.   err = Pa_OpenStream (&dev->stream,
  169.                        NULL,              /* Input parameters */
  170.                        &outputParams,
  171.                        sample_rate,
  172.                        period_size,
  173.                        paNoFlag,
  174.                        fluid_portaudio_run,
  175.                        dev);
  176.   if (err != paNoError)
  177.   {
  178.     FLUID_LOG (FLUID_ERR, "Error opening PortAudio stream: %s",
  179.                Pa_GetErrorText (err));
  180.     goto error_recovery;
  181.   }
  182.   err = Pa_StartStream (dev->stream);
  183.   if (err != paNoError)
  184.   {
  185.     FLUID_LOG (FLUID_ERR, "Error starting PortAudio stream: %s",
  186.                Pa_GetErrorText (err));
  187.     goto error_recovery;
  188.   }
  189.   if (device) FLUID_FREE (device);      /* -- free device name */
  190.   
  191.   return (fluid_audio_driver_t *)dev;
  192. error_recovery:
  193.   if (device) FLUID_FREE (device);      /* -- free device name */
  194.   delete_fluid_portaudio_driver ((fluid_audio_driver_t *)dev);
  195.   return NULL;
  196. }
  197. /* PortAudio callback
  198.  * fluid_portaudio_run
  199.  */
  200. static int
  201. fluid_portaudio_run (const void *input, void *output, unsigned long frameCount,
  202.                      const PaStreamCallbackTimeInfo* timeInfo,
  203.                      PaStreamCallbackFlags statusFlags, void *userData)
  204. {
  205.   fluid_portaudio_driver_t *dev = (fluid_portaudio_driver_t *)userData;
  206.   /* it's as simple as that: */
  207.   dev->read (dev->synth, frameCount, output, 0, 2, output, 1, 2);
  208.   return 0;
  209. }
  210. /*
  211.  * delete_fluid_portaudio_driver
  212.  */
  213. int
  214. delete_fluid_portaudio_driver(fluid_audio_driver_t *p)
  215. {
  216.   fluid_portaudio_driver_t* dev;
  217.   PaError err;
  218.   dev = (fluid_portaudio_driver_t*)p;
  219.   if (dev == NULL) return FLUID_OK;
  220.   /* PortAudio section */
  221.   if (dev->stream) Pa_CloseStream (dev->stream);
  222.   err = Pa_Terminate();
  223.   if (err != paNoError)
  224.     printf ("PortAudio termination error: %sn", Pa_GetErrorText (err) );
  225.   FLUID_FREE (dev);
  226.   return FLUID_OK;
  227. }
  228. #endif /*#if PORTAUDIO_SUPPORT */