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

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.  /* 
  21.   * Low-level routines for file output.
  22.   */
  23. #include <stdio.h>
  24. #include "fluidsynth_priv.h"
  25. #include "fluid_synth.h"
  26. #include "fluid_sys.h"
  27. #include "fluid_settings.h"
  28. #if LIBSNDFILE_SUPPORT
  29. #include <sndfile.h>
  30. #endif
  31. struct _fluid_file_renderer_t {
  32. fluid_synth_t* synth;
  33. #if LIBSNDFILE_SUPPORT
  34. SNDFILE* sndfile;
  35. float* buf;
  36. #else
  37. FILE* file;
  38. short* buf;
  39. #endif
  40. int period_size;
  41. int buf_size;
  42. };
  43. #if LIBSNDFILE_SUPPORT
  44. /* Default file type used, if none specified and auto extension search fails */
  45. #define FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE   SF_FORMAT_WAV
  46. /* File audio format names.
  47.  * !! Keep in sync with format_ids[] */
  48. const char *format_names[] = {
  49.   "s8",
  50.   "s16",
  51.   "s24",
  52.   "s32",
  53.   "u8",
  54.   "float",
  55.   "double",
  56.   NULL          /* Terminator */
  57. };
  58.   
  59. /* File audio format IDs.
  60.  * !! Keep in sync with format_names[] */
  61. const int format_ids[] = {
  62.   SF_FORMAT_PCM_S8,
  63.   SF_FORMAT_PCM_16,
  64.   SF_FORMAT_PCM_24,
  65.   SF_FORMAT_PCM_32,
  66.   SF_FORMAT_PCM_U8,
  67.   SF_FORMAT_FLOAT,
  68.   SF_FORMAT_DOUBLE
  69. };
  70. /* File endian byte order names.
  71.  * !! Keep in sync with endian_ids[] */
  72. const char *endian_names[] = {
  73.   "auto",
  74.   "little",
  75.   "big",
  76.   "cpu",
  77.   NULL
  78. };
  79. /* File endian byte order ids.
  80.  * !! Keep in sync with endian_names[] */
  81. const int endian_ids[] = {
  82.   SF_ENDIAN_FILE,
  83.   SF_ENDIAN_LITTLE,
  84.   SF_ENDIAN_BIG,
  85.   SF_ENDIAN_CPU
  86. };
  87. static int fluid_file_renderer_parse_options (char *filetype, char *format,
  88.                                               char *endian, char *filename, SF_INFO *info);
  89. static int fluid_file_renderer_find_file_type (char *extension, int *type);
  90. static int fluid_file_renderer_find_valid_format (SF_INFO *info);
  91. #else   /* No libsndfile support */
  92. /* File type names. */
  93. const char *type_names[] = {
  94.   "raw",
  95.   NULL          /* Terminator */
  96. };
  97. /* File audio format names. */
  98. const char *format_names[] = {
  99.   "s16",
  100.   NULL          /* Terminator */
  101. };
  102. /* File endian byte order names. */
  103. const char *endian_names[] = {
  104.   "cpu",
  105.   NULL
  106. };
  107. #endif
  108. void
  109. fluid_file_renderer_settings (fluid_settings_t* settings)
  110. {
  111. #if LIBSNDFILE_SUPPORT
  112.   SF_FORMAT_INFO finfo, cmpinfo;
  113.   int major_count;
  114.   int i, i2;
  115.   const char **np;
  116.   fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.wav",
  117.                               FLUID_HINT_FILENAME, NULL, NULL);
  118.   fluid_settings_register_str(settings, "audio.file.type", "auto", 0, NULL, NULL);
  119.   fluid_settings_register_str(settings, "audio.file.format", "s16", 0, NULL, NULL);
  120.   fluid_settings_register_str(settings, "audio.file.endian", "auto", 0, NULL, NULL);
  121.   fluid_settings_add_option (settings, "audio.file.type", "auto");
  122.   sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int));
  123.   for (i = 0; i < major_count; i++)
  124.   {
  125.     finfo.format = i;
  126.     sf_command (NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof (finfo));
  127.     /* Check for duplicates */
  128.     for (i2 = 0; i2 < i; i2++)
  129.     {
  130.       cmpinfo.format = i2;
  131.       sf_command (NULL, SFC_GET_FORMAT_MAJOR, &cmpinfo, sizeof (cmpinfo));
  132.       if (FLUID_STRCMP (cmpinfo.extension, finfo.extension) == 0)
  133.         break;
  134.     }
  135.     if (i2 == i)
  136.       fluid_settings_add_option (settings, "audio.file.type", finfo.extension);
  137.   }
  138.   for (np = format_names; *np; np++)
  139.     fluid_settings_add_option (settings, "audio.file.format", *np);
  140.   for (np = endian_names; *np; np++)
  141.     fluid_settings_add_option (settings, "audio.file.endian", *np);
  142. #else
  143.   fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL);
  144.   fluid_settings_register_str(settings, "audio.file.type", "raw", 0, NULL, NULL);
  145.   fluid_settings_add_option (settings, "audio.file.type", "raw");
  146.   fluid_settings_register_str(settings, "audio.file.format", "s16", 0, NULL, NULL);
  147.   fluid_settings_add_option (settings, "audio.file.format", "s16");
  148.   fluid_settings_register_str(settings, "audio.file.endian", "cpu", 0, NULL, NULL);
  149.   fluid_settings_add_option (settings, "audio.file.endian", "cpu");
  150. #endif
  151. }
  152. /**
  153.  * Create a new file renderer and open the file.
  154.  * @param synth The synth that creates audio data.
  155.  * @return the new object, or NULL on failure
  156.  * @since 1.1.0
  157.  *
  158.  * NOTE: Available file types and formats depends on if libfluidsynth was
  159.  * built with libsndfile support or not.  If not then only RAW 16 bit output is
  160.  * supported.
  161.  *
  162.  * Uses the following settings from the synth object:
  163.  *   - audio.file.name: Output filename
  164.  *   - audio.file.type: File type, "auto" tries to determine type from filename
  165.  *     extension with fallback to "wav".
  166.  *   - audio.file.format: Audio format
  167.  *   - audio.file.endian: Endian byte order, "auto" for file type's default byte order
  168.  *   - audio.period-size: Size of audio blocks to process
  169.  *   - synth.sample-rate: Sample rate to use
  170.  */
  171. fluid_file_renderer_t *
  172. new_fluid_file_renderer(fluid_synth_t* synth)
  173. {
  174. #if LIBSNDFILE_SUPPORT
  175. char *type, *format, *endian;
  176. SF_INFO info;
  177. double samplerate;
  178. int retval;
  179. #endif
  180.         char *filename = NULL;
  181. fluid_file_renderer_t* dev;
  182. fluid_return_val_if_fail (synth != NULL, NULL);
  183. fluid_return_val_if_fail (synth->settings != NULL, NULL);
  184. dev = FLUID_NEW(fluid_file_renderer_t);
  185. if (dev == NULL) {
  186. FLUID_LOG(FLUID_ERR, "Out of memory");
  187. return NULL;
  188. }
  189. FLUID_MEMSET(dev, 0, sizeof(fluid_file_renderer_t));
  190. dev->synth = synth;
  191. fluid_settings_getint (synth->settings, "audio.period-size", &dev->period_size);
  192. #if LIBSNDFILE_SUPPORT
  193. dev->buf_size = 2 * dev->period_size * sizeof (float);
  194. dev->buf = FLUID_ARRAY(float, 2 * dev->period_size);
  195. #else
  196. dev->buf_size = 2 * dev->period_size * sizeof (short);
  197. dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
  198. #endif
  199. if (dev->buf == NULL) {
  200. FLUID_LOG(FLUID_ERR, "Out of memory");
  201. goto error_recovery;
  202. }
  203. fluid_settings_dupstr (synth->settings, "audio.file.name", &filename);
  204. if (filename == NULL) {
  205. FLUID_LOG(FLUID_ERR, "No file name specified");
  206. goto error_recovery;
  207. }
  208. #if LIBSNDFILE_SUPPORT
  209. memset (&info, 0, sizeof (info));
  210.         info.format = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE | SF_FORMAT_PCM_16;
  211. fluid_settings_dupstr (synth->settings, "audio.file.type", &type);
  212. fluid_settings_dupstr (synth->settings, "audio.file.format", &format);
  213. fluid_settings_dupstr (synth->settings, "audio.file.endian", &endian);
  214. retval = fluid_file_renderer_parse_options (type, format, endian, filename, &info);
  215. if (type) FLUID_FREE (type);
  216. if (format) FLUID_FREE (format);
  217. if (endian) FLUID_FREE (endian);
  218. if (!retval) goto error_recovery;
  219. fluid_settings_getnum (synth->settings, "synth.sample-rate", &samplerate);
  220. info.samplerate = samplerate + 0.5;
  221. info.channels = 2;
  222. /* Search for valid format for given file type, if invalid and no format was specified.
  223.  * To handle Ogg/Vorbis and possibly future file types with new formats.
  224.  * Checking if format is SF_FORMAT_PCM_16 isn't a fool proof way to check if
  225.  * format was specified or not (if user specifies "s16" itself), but should suffice. */
  226. if (!sf_format_check (&info)
  227.             && ((info.format & SF_FORMAT_SUBMASK) != SF_FORMAT_PCM_16
  228.                 || !fluid_file_renderer_find_valid_format (&info)))
  229. {
  230.   FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file format settings");
  231.   goto error_recovery;
  232. }
  233. dev->sndfile = sf_open (filename, SFM_WRITE, &info);
  234. if (!dev->sndfile)
  235. {
  236.   FLUID_LOG(FLUID_ERR, "Failed to open audio file '%s' for writing", filename);
  237.           goto error_recovery;
  238. }
  239. /* Turn on clipping and normalization of floats (-1.0 - 1.0) */
  240. sf_command (dev->sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE);
  241. sf_command (dev->sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
  242. #else
  243. dev->file = fopen(filename, "wb");
  244. if (dev->file == NULL) {
  245. FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename);
  246. goto error_recovery;
  247. }
  248. #endif
  249. return dev;
  250.  error_recovery:
  251. if (filename) FLUID_FREE (filename);
  252. delete_fluid_file_renderer(dev);
  253. return NULL;
  254. }
  255. /**
  256.  * Close file and destroy a file renderer object.
  257.  * @param dev File renderer object.
  258.  * @since 1.1.0
  259.  */
  260. void delete_fluid_file_renderer(fluid_file_renderer_t* dev)
  261. {
  262. if (dev == NULL) {
  263. return;
  264. }
  265. #if LIBSNDFILE_SUPPORT
  266. if (dev->sndfile != NULL) {
  267. int retval = sf_close (dev->sndfile);
  268. if (retval != 0) FLUID_LOG (FLUID_WARN, "Error closing audio file: %s",
  269.     sf_error_number (retval));
  270.         }
  271. #else
  272. if (dev->file != NULL) {
  273. fclose(dev->file);
  274. }
  275. #endif
  276. if (dev->buf != NULL) {
  277. FLUID_FREE(dev->buf);
  278. }
  279. FLUID_FREE(dev);
  280. return;
  281. }
  282. /**
  283.  * Write period_size samples to file.
  284.  * @param dev File renderer instance
  285.  * @return #FLUID_OK or #FLUID_FAILED if an error occurred
  286.  * @since 1.1.0
  287.  */
  288. int
  289. fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
  290. {
  291. #if LIBSNDFILE_SUPPORT
  292. int n;
  293. fluid_synth_write_float(dev->synth, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
  294. n = sf_writef_float (dev->sndfile, dev->buf, dev->period_size);
  295. if (n != dev->period_size) {
  296. FLUID_LOG (FLUID_ERR, "Audio file write error: %s",
  297.    sf_strerror (dev->sndfile));
  298. return FLUID_FAILED;
  299. }
  300. return FLUID_OK;
  301. #else   /* No libsndfile support */
  302. int n, offset;
  303. fluid_synth_write_s16(dev->synth, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
  304. for (offset = 0; offset < dev->buf_size; offset += n) {
  305. n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file);
  306. if (n < 0) {
  307. FLUID_LOG(FLUID_ERR, "Audio output file write error: %s",
  308.   strerror (errno));
  309. return FLUID_FAILED;
  310. }
  311. }
  312. return FLUID_OK;
  313. #endif
  314. }
  315. #if LIBSNDFILE_SUPPORT
  316. /**
  317.  * Parse a colon separated format string and configure an SF_INFO structure accordingly.
  318.  * @param filetype File type string (NULL or "auto" to attempt to identify format
  319.  *   by filename extension, with fallback to "wav")
  320.  * @param format File audio format string or NULL to use "s16"
  321.  * @param endian File endian string or NULL to use "auto" which uses the file type's
  322.  *   default endian byte order.
  323.  * @param filename File name (used by "auto" type to determine type, based on extension)
  324.  * @param info Audio file info structure to configure
  325.  * @return TRUE on success, FALSE otherwise
  326.  */
  327. static int
  328. fluid_file_renderer_parse_options (char *filetype, char *format, char *endian,
  329.                                    char *filename, SF_INFO *info)
  330. {
  331.   int type = -1;        /* -1 indicates "auto" type */
  332.   char *s;
  333.   int i;
  334.   /* If "auto" type, then use extension to search for a match */
  335.   if (!filetype || FLUID_STRCMP (filetype, "auto") == 0)
  336.   {
  337.     type = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE;
  338.     s = FLUID_STRRCHR (filename, '.');
  339.     if (s && s[1] != '')
  340.     {
  341.       if (!fluid_file_renderer_find_file_type (s + 1, &type))
  342.         FLUID_LOG (FLUID_WARN, "Failed to determine audio file type from filename, defaulting to WAV");
  343.     }
  344.   }
  345.   else if (!fluid_file_renderer_find_file_type (filetype, &type))
  346.   {
  347.     FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file type '%s'", filetype);
  348.     return FALSE;
  349.   }
  350.   info->format = (info->format & ~SF_FORMAT_TYPEMASK) | type;
  351.   /* Look for subtype */
  352.   if (format)
  353.   {
  354.     for (i = 0; format_names[i]; i++)
  355.       if (FLUID_STRCMP (format, format_names[i]) == 0)
  356.         break;
  357.     if (!format_names[i])
  358.     {
  359.       FLUID_LOG (FLUID_ERR, "Invalid or unsupported file audio format '%s'", format);
  360.       return FALSE;
  361.     }
  362.     info->format = (info->format & ~SF_FORMAT_SUBMASK) | format_ids[i];
  363.   }
  364. #if LIBSNDFILE_HASVORBIS
  365.   /* Force subformat to vorbis as nothing else would make sense currently */
  366.   if ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_OGG) {
  367.     info->format = (info->format & ~SF_FORMAT_SUBMASK) | SF_FORMAT_VORBIS;
  368.   }
  369. #endif
  370.   /* Look for endian */
  371.   if (endian)
  372.   {
  373.     for (i = 0; endian_names[i]; i++)
  374.       if (FLUID_STRCMP (endian, endian_names[i]) == 0)
  375.         break;
  376.     if (!endian_names[i])
  377.     {
  378.       FLUID_LOG (FLUID_ERR, "Invalid or unsupported endian byte order '%s'", endian);
  379.       return FALSE;
  380.     }
  381.     info->format = (info->format & ~SF_FORMAT_ENDMASK) | endian_ids[i];
  382.   }
  383.   return TRUE;
  384. }
  385. /**
  386.  * Searches for a supported libsndfile file type by extension.
  387.  * @param extension The extension string
  388.  * @param ext_len Length of the extension string
  389.  * @param type Location to store the type (unmodified if not found)
  390.  * @return TRUE if found, FALSE otherwise
  391.  */
  392. static int
  393. fluid_file_renderer_find_file_type (char *extension, int *type)
  394. {
  395.   SF_FORMAT_INFO finfo;
  396.   int major_count;
  397.   int i;
  398.   sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int));
  399.   for (i = 0; i < major_count; i++)
  400.   {
  401.     finfo.format = i;
  402.     sf_command (NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof (finfo));
  403.     if (FLUID_STRCMP (extension, finfo.extension) == 0)
  404.       break;
  405.   }
  406.   if (i < major_count)
  407.   {
  408.     *type = finfo.format;
  409.     return TRUE;
  410.   }
  411.   return FALSE;
  412. }
  413. /* Search for a valid audio format for a given file type */
  414. static int
  415. fluid_file_renderer_find_valid_format (SF_INFO *info)
  416. {
  417.   SF_FORMAT_INFO format_info;
  418.   int count, i;
  419.   sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
  420.   for (i = 0; i < count; i++)
  421.   {
  422.     format_info.format = i;
  423.     sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info));
  424.     info->format = (info->format & ~SF_FORMAT_SUBMASK) | format_info.format;
  425.     if (sf_format_check (info)) return TRUE;
  426.   }
  427.   return FALSE;
  428. }
  429. #endif