fluid_sndmgr.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:10k
- /* FluidSynth - A Software Synthesizer
- *
- * Copyright (C) 2003 Peter Hanappe and others.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307, USA
- */
- /* fluid_sndmgr.c
- *
- * Driver for MacOS Classic
- */
- #if SNDMAN_SUPPORT
- #include "fluid_synth.h"
- #include "fluid_adriver.h"
- #include "fluid_settings.h"
- #include <Sound.h>
- typedef struct {
- fluid_audio_driver_t driver;
- SndDoubleBufferHeader2* doubleHeader;
- SndDoubleBackUPP doubleCallbackProc;
- SndChannelPtr channel;
- int callback_is_audio_func;
- void* data;
- fluid_audio_func_t callback;
- float* convbuffers[2];
- int bufferByteSize;
- int bufferFrameSize;
- } fluid_sndmgr_audio_driver_t;
- fluid_audio_driver_t* new_fluid_sndmgr_audio_driver(fluid_settings_t* settings,
- fluid_synth_t* synth);
- fluid_audio_driver_t* new_fluid_sndmgr_audio_driver2(fluid_settings_t* settings,
- fluid_audio_func_t func,
- void* data);
- int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p);
- void pascal fluid_sndmgr_callback(SndChannelPtr chan, SndDoubleBufferPtr doubleBuffer);
- Fixed fluid_sndmgr_double_to_fix(long double theLD);
- /*
- * generic new : returns error
- */
- int
- start_fluid_sndmgr_audio_driver(fluid_settings_t* settings,
- fluid_sndmgr_audio_driver_t* dev,
- int buffer_size)
- {
- int i;
- SndDoubleBufferHeader2* doubleHeader = NULL;
- SndDoubleBufferPtr doubleBuffer = NULL;
- OSErr err;
- SndChannelPtr channel = NULL;
- double sample_rate;
- fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
- dev->doubleCallbackProc = NewSndDoubleBackProc(fluid_sndmgr_callback);
- /* the channel */
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@2");
- err = SndNewChannel(&channel, sampledSynth, initStereo, NULL);
- if ((err != noErr) || (channel == NULL)) {
- FLUID_LOG(FLUID_ERR, "Failed to allocate a sound channel (error %i)", err);
- return err;
- }
- /* the double buffer struct */
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@3");
- doubleHeader = FLUID_NEW(SndDoubleBufferHeader2);
- if (doubleHeader == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return -1;
- }
- doubleHeader->dbhBufferPtr[0] = NULL;
- doubleHeader->dbhBufferPtr[1] = NULL;
- doubleHeader->dbhNumChannels = 2;
- doubleHeader->dbhSampleSize = 16;
- doubleHeader->dbhCompressionID = 0;
- doubleHeader->dbhPacketSize = 0;
- doubleHeader->dbhSampleRate = fluid_sndmgr_double_to_fix((long double) sample_rate);
- doubleHeader->dbhDoubleBack = dev->doubleCallbackProc;
- doubleHeader->dbhFormat = 0;
- /* prepare dev */
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@4");
- dev->doubleHeader = doubleHeader;
- dev->channel = channel;
- dev->bufferFrameSize = buffer_size;
- dev->bufferByteSize = buffer_size * 2 * 2;
- /* the 2 doublebuffers */
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@5");
- for (i = 0; i < 2; i++) {
- doubleBuffer = (SndDoubleBufferPtr) FLUID_MALLOC(sizeof(SndDoubleBuffer)
- + dev->bufferByteSize);
- if (doubleBuffer == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return -1;
- }
- doubleBuffer->dbNumFrames = 0;
- doubleBuffer->dbFlags = 0;
- doubleBuffer->dbUserInfo[0] = (long) dev;
- doubleHeader->dbhBufferPtr[i] = doubleBuffer;
- CallSndDoubleBackProc(doubleHeader->dbhDoubleBack, channel, doubleBuffer);
- }
- /* start */
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@6");
- err = SndPlayDoubleBuffer(channel, (SndDoubleBufferHeader *)doubleHeader);
- if (err != noErr) {
- FLUID_LOG(FLUID_ERR, "Failed to start the sound driver (error %i)", err);
- return err;
- }
- FLUID_LOG(FLUID_DBG, "FLUID-SndManager@7");
- return 0;
- }
- /*
- * new_fluid_sndmgr_audio_driver
- * This implementation used the 16bit format.
- */
- fluid_audio_driver_t*
- new_fluid_sndmgr_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
- {
- fluid_sndmgr_audio_driver_t* dev = NULL;
- int period_size, periods, buffer_size;
- /* check the format */
- if (!fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) {
- FLUID_LOG(FLUID_ERR, "Unhandled sample format");
- return NULL;
- }
- /* compute buffer size */
- fluid_settings_getint(settings, "audio.period-size", &period_size);
- fluid_settings_getint(settings, "audio.periods", &periods);
- buffer_size = period_size*periods;
- /* allocated dev */
- dev = FLUID_NEW(fluid_sndmgr_audio_driver_t);
- if (dev == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return NULL;
- }
- FLUID_MEMSET(dev, 0, sizeof(fluid_sndmgr_audio_driver_t));
- dev->callback_is_audio_func = false;
- dev->data = (void *)synth;
- dev->callback = NULL;
- if (start_fluid_sndmgr_audio_driver(settings, dev, buffer_size) != 0) {
- delete_fluid_sndmgr_audio_driver((fluid_audio_driver_t*)dev);
- return NULL;
- }
- return (fluid_audio_driver_t*)dev;
- }
- /*
- * new_fluid_sndmgr_audio_driver2
- *
- * This implementation used the audio_func float format, with
- * conversion from float to 16bits in the driver.
- */
- fluid_audio_driver_t*
- new_fluid_sndmgr_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
- {
- fluid_sndmgr_audio_driver_t* dev = NULL;
- int period_size, periods, buffer_size;
- /* compute buffer size */
- fluid_settings_getint(settings, "audio.period-size", &period_size);
- fluid_settings_getint(settings, "audio.periods", &periods);
- buffer_size = period_size*periods;
- /* allocated dev */
- dev = FLUID_NEW(fluid_sndmgr_audio_driver_t);
- if (dev == NULL) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- return NULL;
- }
- FLUID_MEMSET(dev, 0, sizeof(fluid_sndmgr_audio_driver_t));
- /* allocate the conversion buffers */
- dev->convbuffers[0] = FLUID_ARRAY(float, buffer_size);
- dev->convbuffers[1] = FLUID_ARRAY(float, buffer_size);
- if ((dev->convbuffers[0] == NULL) || (dev->convbuffers[1] == NULL)) {
- FLUID_LOG(FLUID_PANIC, "Out of memory");
- goto error_recovery;
- }
- dev->callback_is_audio_func = true;
- dev->data = data;
- dev->callback = func;
- if (start_fluid_sndmgr_audio_driver(settings, dev, buffer_size) != 0) {
- goto error_recovery;
- }
- return (fluid_audio_driver_t*)dev;
- error_recovery:
- delete_fluid_sndmgr_audio_driver((fluid_audio_driver_t*)dev);
- return NULL;
- }
- /*
- * delete_fluid_sndmgr_audio_driver
- */
- int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p)
- {
- fluid_sndmgr_audio_driver_t* dev = (fluid_sndmgr_audio_driver_t*) p;
- if (dev != NULL) {
- if (dev->channel != NULL) {
- SndDisposeChannel(dev->channel, 1);
- }
- if (dev->doubleCallbackProc != NULL) {
- DisposeRoutineDescriptor(dev->doubleCallbackProc);
- }
- if (dev->doubleHeader != NULL) {
- if(dev->doubleHeader->dbhBufferPtr[0] != NULL) {
- FLUID_FREE(dev->doubleHeader->dbhBufferPtr[0]);
- }
- if (dev->doubleHeader->dbhBufferPtr[1] != NULL) {
- FLUID_FREE(dev->doubleHeader->dbhBufferPtr[1]);
- }
- FLUID_FREE(dev->doubleHeader);
- }
- if (dev->convbuffers[0] != NULL) {
- FLUID_FREE(dev->convbuffers[0]);
- }
- if (dev->convbuffers[1] != NULL) {
- FLUID_FREE(dev->convbuffers[1]);
- }
- FLUID_FREE(dev);
- }
- return 0;
- }
- /*
- * fluid_sndmgr_callback
- *
- */
- void pascal fluid_sndmgr_callback(SndChannelPtr chan, SndDoubleBufferPtr doubleBuffer)
- {
- fluid_sndmgr_audio_driver_t* dev;
- signed short* buf;
- float* left;
- float* right;
- float v;
- int i, k, buffer_size;
- dev = (fluid_sndmgr_audio_driver_t*) doubleBuffer->dbUserInfo[0];
- buf = (signed short*)doubleBuffer->dbSoundData;
- buffer_size = dev->bufferFrameSize;
- if (dev->callback_is_audio_func) {
- /* float API : conversion to signed short */
- left = dev->convbuffers[0];
- right = dev->convbuffers[1];
- (*dev->callback)(dev->data, buffer_size, 0, NULL, 2, dev->convbuffers);
- for (i = 0, k = 0; i < buffer_size; i++) {
- v = 32767.0f * left[i];
- fluid_clip(v, -32768.0f, 32767.0f);
- buf[k++] = (signed short) v;
- v = 32767.0f * right[i];
- fluid_clip(v, -32768.0f, 32767.0f);
- buf[k++] = (signed short) v;
- }
- } else {
- /* let the synth do the convertion */
- fluid_synth_write_s16((fluid_synth_t*)dev->data, buffer_size, buf, 0, 2, buf, 1, 2);
- }
- doubleBuffer->dbFlags = doubleBuffer->dbFlags | dbBufferReady;
- doubleBuffer->dbNumFrames = buffer_size;
- }
- /*
- * fluid_sndmgr_double_to_fix
- *
- * A Fixed number is of the type 12345.67890. It is 32 bits in size with the
- * high order bits representing the significant value (that before the point)
- * and the lower 16 bits representing the fractional part of the number.
- * The Sound Manager further complicates matters by using Fixed numbers, but
- * needing to represent numbers larger than what the Fixed is capable of.
- * To do this the Sound Manager treats the sign bit as having the value 32768
- * which will cause any number greater or equal to 32768 to look like it is
- * negative.
- * This routine is designed to "do the right thing" and convert any long double
- * into the Fixed number it represents.
- * long double is the input type because AIFF files use extended80 numbers and
- * there are routines that will convert from an extended80 to a long double.
- * A long double has far greater precision than a Fixed, so any number whose
- * significant or fraction is larger than 65535 will not convert correctly.
- */
- #define _MAX_VALUE 65535
- #define _BITS_PER_BYTE 8
- Fixed fluid_sndmgr_double_to_fix(long double theLD) {
- unsigned long theResult = 0;
- unsigned short theSignificant = 0, theFraction = 0;
- if (theLD < _MAX_VALUE) {
- theSignificant = theLD;
- theFraction = theLD - theSignificant;
- if (theFraction > _MAX_VALUE) {
- /* Won't be able to convert */
- theSignificant = 0;
- theFraction = 0;
- }
- }
- theResult |= theSignificant;
- theResult = theResult << (sizeof (unsigned short) * _BITS_PER_BYTE);
- theResult |= theFraction;
- return theResult;
- }
- #endif