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/* fluid_aufile.c 22 * 23 * Audio driver, outputs the audio to a file (non real-time) 24 * 25 */ 26 27#include "fluid_adriver.h" 28#include "fluid_settings.h" 29#include "fluid_sys.h" 30#include <stdio.h> 31 32 33/** fluid_file_audio_driver_t 34 * 35 * This structure should not be accessed directly. Use audio port 36 * functions instead. 37 */ 38typedef struct { 39 fluid_audio_driver_t driver; 40 fluid_audio_func_t callback; 41 void* data; 42 int period_size; 43 double sample_rate; 44 FILE* file; 45 fluid_timer_t* timer; 46 float* left; 47 float* right; 48 short* buf; 49 int buf_size; 50 unsigned int samples; 51} fluid_file_audio_driver_t; 52 53 54fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings, 55 fluid_synth_t* synth); 56 57int delete_fluid_file_audio_driver(fluid_audio_driver_t* p); 58void fluid_file_audio_driver_settings(fluid_settings_t* settings); 59static int fluid_file_audio_run_s16(void* d, unsigned int msec); 60 61/************************************************************** 62 * 63 * 'file' audio driver 64 * 65 */ 66 67void fluid_file_audio_driver_settings(fluid_settings_t* settings) 68{ 69 fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL); 70} 71 72 73fluid_audio_driver_t* 74new_fluid_file_audio_driver(fluid_settings_t* settings, 75 fluid_synth_t* synth) 76{ 77 fluid_file_audio_driver_t* dev; 78 int err; 79 char* filename; 80 int msec; 81 82 dev = FLUID_NEW(fluid_file_audio_driver_t); 83 if (dev == NULL) { 84 FLUID_LOG(FLUID_ERR, "Out of memory"); 85 return NULL; 86 } 87 FLUID_MEMSET(dev, 0, sizeof(fluid_file_audio_driver_t)); 88 89 fluid_settings_getint(settings, "audio.period-size", &dev->period_size); 90 fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate); 91 92 dev->data = synth; 93 dev->callback = (fluid_audio_func_t) fluid_synth_process; 94 dev->samples = 0; 95 dev->left = FLUID_ARRAY(float, dev->period_size); 96 dev->right = FLUID_ARRAY(float, dev->period_size); 97 dev->buf = FLUID_ARRAY(short, 2 * dev->period_size); 98 dev->buf_size = 2 * dev->period_size * sizeof(short); 99 100 if (fluid_settings_getstr(settings, "audio.file.name", &filename) == 0) { 101 FLUID_LOG(FLUID_ERR, "No file name specified"); 102 goto error_recovery; 103 } 104 105 dev->file = fopen(filename, "wb"); 106 if (dev->file == NULL) { 107 FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename); 108 goto error_recovery; 109 } 110 111 msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0); 112 dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, 1, 0); 113 if (dev->timer == NULL) { 114 FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread."); 115 goto error_recovery; 116 } 117 118 return (fluid_audio_driver_t*) dev; 119 120 error_recovery: 121 delete_fluid_file_audio_driver((fluid_audio_driver_t*) dev); 122 return NULL; 123} 124 125int delete_fluid_file_audio_driver(fluid_audio_driver_t* p) 126{ 127 fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) p; 128 129 if (dev == NULL) { 130 return FLUID_OK; 131 } 132 133 if (dev->timer != NULL) { 134 delete_fluid_timer(dev->timer); 135 } 136 137 if (dev->file != NULL) { 138 fclose(dev->file); 139 } 140 141 if (dev->left != NULL) { 142 FLUID_FREE(dev->left); 143 } 144 145 if (dev->right != NULL) { 146 FLUID_FREE(dev->right); 147 } 148 149 if (dev->buf != NULL) { 150 FLUID_FREE(dev->buf); 151 } 152 153 FLUID_FREE(dev); 154 return FLUID_OK; 155} 156 157static int fluid_file_audio_run_s16(void* d, unsigned int clock_time) 158{ 159 fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) d; 160 int n, offset; 161 unsigned int sample_time; 162 163 sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0); 164 if (sample_time > clock_time) { 165 return 1; 166 } 167 168 fluid_synth_write_s16(dev->data, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2); 169 170 for (offset = 0; offset < dev->buf_size; offset += n) { 171 172 n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file); 173 if (n < 0) { 174 FLUID_LOG(FLUID_ERR, "Audio output file write error: %s", 175 strerror (errno)); 176 return 0; 177 } 178 } 179 180 dev->samples += dev->period_size; 181 182 return 1; 183} 184