/*
Copyright (C) 2010-2012 Florian Jung
This file is part of flo's FM synth.
flo's FM synth is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
flo's FM synth 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with flo's FM synth. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "defines.h"
#include "globals.h"
#include "jack.h"
#include "communication.h"
#include "lfos.h"
using namespace std;
//#define DO_DEBUGGING_EVENTS
jack_port_t *midi_in;
jack_port_t *out_port[N_CHANNELS];
#ifdef STEREO
jack_port_t *out_port2[N_CHANNELS];
#endif
jack_client_t *jack_client = NULL;
void manage_program_lock(int prog, bool lock) //TODO woandershinschieben?
{
program_lock[prog]=lock;
if (lock)
for (int i=0;ikill_program(prog);
}
void process_request(request_t request)
{
switch (request.type)
{
case request_t::NONE: break;
case request_t::SUSPEND_PROGRAM:
case request_t::RESUME_PROGRAM:
if (request.prog_or_chan==-1)
for (int i=0;i<128;++i)
manage_program_lock(i,request.type==request_t::SUSPEND_PROGRAM);
else
manage_program_lock(request.prog_or_chan,request.type==request_t::SUSPEND_PROGRAM);
break;
case request_t::PANIC:
if (request.prog_or_chan==-1)
for (int i=0;ipanic();
else
channel[request.prog_or_chan]->panic();
break;
case request_t::RELEASE_ALL:
if (request.prog_or_chan==-1)
for (int i=0;irelease_all();
else
channel[request.prog_or_chan]->release_all();
break;
default:
cout << "ERROR: bad request, ignoring it." << endl;
}
request_finished(0);
}
//connect to jack, init some stuff and get information
void init_jack()
{
jack_client = jack_client_open("flosoftsynth", JackNullOption, NULL);
if (jack_client == NULL)
throw string("Registering client failed");
if (jack_set_process_callback(jack_client, process_callback, 0))
throw string("Registering callback failed");
if (jack_set_xrun_callback(jack_client, xrun_callback, 0))
throw string("Registering xrun-callback failed");
midi_in = jack_port_register(jack_client, MIDI_IN_NAME,
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
if (midi_in == NULL)
throw string ("Registering MIDI IN failed");
for (int i=0;i history;
list::iterator it;
float now=float(jack_get_time())/1000000;
cout << "got an XRUN! if this happens too often, consider reducing CPU usage, for\n example by setting a voice limit or by quitting other programs"<= xrun_n)
{
cout << "PANIC -- TOO MANY XRUNs! killing all voices" << flush;
do_request(request_t(request_t::PANIC, -1));
cout << " (done)" << endl << endl;
history.clear();
}
return 0;
}
#define IGNORE_MIDI_OFFSET
int process_callback(jack_nframes_t nframes, void *notused)
{
#ifdef DO_DEBUGGING_EVENTS
static jack_nframes_t tmp=0, tmp2=0;
#endif
static jack_nframes_t next_cleanup=0;
size_t curr_event=0, n_events, i, chan;
void *inport;
jack_default_audio_sample_t *outbuf[N_CHANNELS];
#ifdef STEREO
jack_default_audio_sample_t *outbuf2[N_CHANNELS];
#endif
jack_midi_event_t event;
jack_nframes_t lastframe;
lastframe=jack_last_frame_time(jack_client);
if (nframes <= 0) {
output_note ("NOTE: Process callback called with nframes = 0; bug in JACK?");
return 0;
}
if (request_available())
process_request(get_request());
for (i=0;i=next_cleanup)
{
next_cleanup=lastframe+cleanup_interval;
for (i=0;icleanup();
}
#ifdef DO_DEBUGGING_EVENTS
if (tmp==0) //DEBUG !!!
{
tmp=lastframe;
channel[0]->set_controller(5,10);
channel[0]->set_controller(65,127);
channel[0]->event(0x90,80,64);
// channel[0]->event(0x90,84,64);
}
else if (tmp2==0)
{
if (lastframe>tmp+44100*1)
{
tmp2=1;
cout << "BÄÄM" << endl;
channel[0]->event(0x90,84,64);
}
}
else if (tmp2==1)
{
if (lastframe>tmp+44100*2)
{
tmp2=2;
channel[0]->event(0x90,87,5);
channel[0]->set_controller(58, 0);
cout << "BÄÄM2" << endl;
}
}
else if (tmp2==2)
{
if (lastframe>tmp+44100*3)
{
tmp2=3;
channel[0]->event(0x90,90,127);
cout << "BÄÄM2" << endl;
}
}
else if (tmp2==3)
{
if (lastframe>tmp+44100*4)
{
tmp2=4;
channel[0]->event(0x90,60,96);
cout << "BÄÄM2" << endl;
}
}
else if (tmp2==4)
{
if (lastframe>tmp+44100*5)
{
tmp2=5;
channel[0]->event(0x90,63,32);
cout << "BÄÄM2" << endl;
}
}
else if (tmp2==5)
{
if (lastframe>tmp+44100*6)
{
tmp2=6;
channel[0]->event(0x90,66,60);
cout << "BÄÄM2" << endl;
}
}
else
{
if (lastframe>tmp+44100*8)
{
cout << "finished" << endl;
exit(0);
}
}
#endif
#ifdef FRAMESKIP
if (outtemp_nframes_left)
{
jack_nframes_t real_nframes;
if (outtemp_nframes_left > nframes)
{
real_nframes=nframes;
outtemp_nframes_left-=nframes;
}
else
{
real_nframes=outtemp_nframes_left;
outtemp_nframes_left=0;
}
for (i=0;i=event.time))
{
output_verbose("processing event #"+IntToStr(curr_event)+" of "+IntToStr(n_events)+" events");
if (event.size > 3)
{
output_verbose(" Ignoring MIDI message longer than three bytes, probably a SysEx.");
}
else
{
chan=event.buffer[0] & 0x0F;
output_verbose(" channel="+IntToStr(chan)+", data is "+IntToStrHex(event.buffer[0])+" "+IntToStrHex(event.buffer[1])+" "+IntToStrHex(event.buffer[2]));
channel[chan]->event(event.buffer[0], event.buffer[1], event.buffer[2]);
}
--n_events;
++curr_event;
//as long as there are some events left and getting one fails, get the next
while ((n_events) && (jack_midi_event_get(&event, inport, curr_event /*, nframes */)))
{
output_note("NOTE2: lost a note :(");
--n_events;
++curr_event;
}
}
maybe_calc_lfos();
for (int j=0;jget_sample())/ONE*VOL_FACTOR;
#else
jack_default_audio_sample_t sample=jack_default_audio_sample_t(channel[j]->get_sample())/ONE*VOL_FACTOR;
outbuf[j][i]=channel[j]->balL*sample;
outbuf2[j][i]=channel[j]->balR*sample;
#endif // if the above changes, (1) must also change
#ifdef FRAMESKIP
for (size_t k=i+frameskip-1;k>i;--k)
{
outbuf[j][k]=outbuf[j][i];
#ifdef STEREO
outbuf2[j][k]=outbuf2[j][i];
#endif
}
#endif
}
}
#ifdef FRAMESKIP
if (i!=nframes) // nicht aufgegangen?
{
for (int j=0;jget_sample())/ONE*VOL_FACTOR;
#else
jack_default_audio_sample_t sample=jack_default_audio_sample_t(channel[j]->get_sample())/ONE*VOL_FACTOR;
outtemp[j]=channel[j]->balL*sample;
outtemp2[j]=channel[j]->balR*sample;
#endif
}
outtemp_nframes_left=frameskip-nframes+i;
for (i=i; i