200 lines
5.9 KiB
C
200 lines
5.9 KiB
C
/* 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 Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA
|
|
*/
|
|
|
|
#include "fluid_rvoice_event.h"
|
|
#include "fluid_rvoice.h"
|
|
#include "fluid_rvoice_mixer.h"
|
|
#include "fluid_iir_filter.h"
|
|
#include "fluid_lfo.h"
|
|
#include "fluid_adsr_env.h"
|
|
|
|
static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event);
|
|
|
|
static FLUID_INLINE void
|
|
fluid_rvoice_event_dispatch(fluid_rvoice_event_t *event)
|
|
{
|
|
event->method(event->object, event->param);
|
|
}
|
|
|
|
|
|
/**
|
|
* In order to be able to push more than one event atomically,
|
|
* use push for all events, then use flush to commit them to the
|
|
* queue. If threadsafe is false, all events are processed immediately. */
|
|
int
|
|
fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
|
|
fluid_rvoice_function_t method, void *object, int intparam,
|
|
fluid_real_t realparam)
|
|
{
|
|
fluid_rvoice_event_t local_event;
|
|
|
|
local_event.method = method;
|
|
local_event.object = object;
|
|
local_event.param[0].i = intparam;
|
|
local_event.param[1].real = realparam;
|
|
|
|
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
|
}
|
|
|
|
int
|
|
fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, fluid_rvoice_function_t method, void *object, fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
|
|
{
|
|
fluid_rvoice_event_t local_event;
|
|
|
|
local_event.method = method;
|
|
local_event.object = object;
|
|
FLUID_MEMCPY(&local_event.param, param, sizeof(*param) * MAX_EVENT_PARAMS);
|
|
|
|
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
|
}
|
|
|
|
int
|
|
fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
|
|
fluid_rvoice_function_t method, void *object, void *ptr)
|
|
{
|
|
fluid_rvoice_event_t local_event;
|
|
|
|
local_event.method = method;
|
|
local_event.object = object;
|
|
local_event.param[0].ptr = ptr;
|
|
|
|
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
|
}
|
|
|
|
static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event)
|
|
{
|
|
fluid_rvoice_event_t *event;
|
|
int old_queue_stored = fluid_atomic_int_add(&handler->queue_stored, 1);
|
|
|
|
event = fluid_ringbuffer_get_inptr(handler->queue, old_queue_stored);
|
|
|
|
if(event == NULL)
|
|
{
|
|
fluid_atomic_int_add(&handler->queue_stored, -1);
|
|
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
|
return FLUID_FAILED; // Buffer full...
|
|
}
|
|
|
|
FLUID_MEMCPY(event, src_event, sizeof(*event));
|
|
|
|
return FLUID_OK;
|
|
}
|
|
|
|
|
|
void
|
|
fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice)
|
|
{
|
|
fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
|
|
|
|
if(vptr == NULL)
|
|
{
|
|
return; // Buffer full
|
|
}
|
|
|
|
*vptr = rvoice;
|
|
fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
|
|
}
|
|
|
|
fluid_rvoice_eventhandler_t *
|
|
new_fluid_rvoice_eventhandler(int queuesize,
|
|
int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
|
|
{
|
|
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
|
|
|
if(eventhandler == NULL)
|
|
{
|
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
|
return NULL;
|
|
}
|
|
|
|
eventhandler->mixer = NULL;
|
|
eventhandler->queue = NULL;
|
|
eventhandler->finished_voices = NULL;
|
|
|
|
fluid_atomic_int_set(&eventhandler->queue_stored, 0);
|
|
|
|
eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
|
|
sizeof(fluid_rvoice_t *));
|
|
|
|
if(eventhandler->finished_voices == NULL)
|
|
{
|
|
goto error_recovery;
|
|
}
|
|
|
|
eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
|
|
|
|
if(eventhandler->queue == NULL)
|
|
{
|
|
goto error_recovery;
|
|
}
|
|
|
|
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
|
|
|
|
if(eventhandler->mixer == NULL)
|
|
{
|
|
goto error_recovery;
|
|
}
|
|
|
|
return eventhandler;
|
|
|
|
error_recovery:
|
|
delete_fluid_rvoice_eventhandler(eventhandler);
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *handler)
|
|
{
|
|
return fluid_ringbuffer_get_count(handler->queue);
|
|
}
|
|
|
|
|
|
/**
|
|
* Call fluid_rvoice_event_dispatch for all events in queue
|
|
* @return number of events dispatched
|
|
*/
|
|
int
|
|
fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *handler)
|
|
{
|
|
fluid_rvoice_event_t *event;
|
|
int result = 0;
|
|
|
|
while(NULL != (event = fluid_ringbuffer_get_outptr(handler->queue)))
|
|
{
|
|
fluid_rvoice_event_dispatch(event);
|
|
result++;
|
|
fluid_ringbuffer_next_outptr(handler->queue);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *handler)
|
|
{
|
|
fluid_return_if_fail(handler != NULL);
|
|
|
|
delete_fluid_rvoice_mixer(handler->mixer);
|
|
delete_fluid_ringbuffer(handler->queue);
|
|
delete_fluid_ringbuffer(handler->finished_voices);
|
|
FLUID_FREE(handler);
|
|
}
|