243 lines
7.1 KiB
C++
243 lines
7.1 KiB
C++
/*
|
|
Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net>
|
|
|
|
This program 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
#include "messages.h"
|
|
#include "aeolus.h"
|
|
|
|
//---------------------------------------------------------
|
|
// start
|
|
//---------------------------------------------------------
|
|
|
|
void Aeolus::audio_start ()
|
|
{
|
|
_fsize = 0;
|
|
for (int i = 0; i < _nasect; i++)
|
|
_asectpar [i] = _asectp [i]->get_apar ();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// init
|
|
//---------------------------------------------------------
|
|
|
|
void Aeolus::audio_init(int sampleRate)
|
|
{
|
|
_nplay = 2;
|
|
_fsamp = sampleRate;
|
|
_audiopar[VOLUME] = 0.32f;
|
|
_audiopar[REVSIZE] = 0.075f;
|
|
_revtime = 4.0f;
|
|
_audiopar[REVTIME] = _revtime;
|
|
_audiopar[STPOSIT] = 0.5f;
|
|
_revsize = 0.075;
|
|
|
|
_nasect = NASECT;
|
|
for (int i = 0; i < NASECT; i++) {
|
|
_asectp [i] = new Asection ((float) _fsamp);
|
|
_asectp [i]->set_size (_revsize);
|
|
}
|
|
_hold = KEYS_MASK;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// proc_queue
|
|
// Execute command from the model
|
|
//---------------------------------------------------------
|
|
|
|
void Aeolus::proc_queue (uint32_t k)
|
|
{
|
|
int c = k >> 24;
|
|
int j = (k >> 16) & 255;
|
|
int i = (k >> 8) & 255;
|
|
int b = k & 255;
|
|
|
|
switch (c) {
|
|
case 0: // Single key off.
|
|
key_off (i, b);
|
|
break;
|
|
|
|
case 1: // Single key on.
|
|
key_on (i, b);
|
|
break;
|
|
|
|
case 2: // Conditional key off.
|
|
cond_key_off (j, b);
|
|
break;
|
|
|
|
case 3: // Conditional key on.
|
|
cond_key_on (j, b);
|
|
break;
|
|
|
|
case 4: // Clear bits in division mask.
|
|
_divisp [j]->clr_div_mask (b);
|
|
break;
|
|
|
|
case 5: // Set bits in division mask.
|
|
_divisp [j]->set_div_mask (b);
|
|
break;
|
|
|
|
case 6: // Clear bits in rank mask.
|
|
_divisp [j]->clr_rank_mask (i, b);
|
|
break;
|
|
|
|
case 7: // Set bits in rank mask.
|
|
_divisp [j]->set_rank_mask (i, b);
|
|
break;
|
|
|
|
case 8: // Hold off.
|
|
_hold = KEYS_MASK;
|
|
cond_key_off (HOLD_MASK, HOLD_MASK);
|
|
break;
|
|
|
|
case 9: // Hold on.
|
|
_hold = KEYS_MASK | HOLD_MASK;
|
|
cond_key_on (j, HOLD_MASK);
|
|
break;
|
|
|
|
case 16: // Tremulant on/off.
|
|
if (b)
|
|
_divisp [j]->trem_on ();
|
|
else
|
|
_divisp [j]->trem_off ();
|
|
break;
|
|
|
|
case 17: // Per-division performance controllers.
|
|
qDebug("Aeolus: not impl.");
|
|
#if 0
|
|
if (n < 2)
|
|
return;
|
|
//TODO u.i = Q->read (1);
|
|
//TODO Q->read_commit (2);
|
|
switch (i) {
|
|
case 0: _divisp [j]->set_swell (u.f); break;
|
|
case 1: _divisp [j]->set_tfreq (u.f); break;
|
|
case 2: _divisp [j]->set_tmodd (u.f); break;
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// process
|
|
//---------------------------------------------------------
|
|
|
|
void Aeolus::process(unsigned nframes, float* out, float*, float*)
|
|
{
|
|
float gain = 1.0;
|
|
|
|
for (int n = 0; n < NNOTES; n++) {
|
|
int m = _keymap[n];
|
|
if (m & 128) {
|
|
m &= 127;
|
|
_keymap [n] = m;
|
|
for (int d = 0; d < _ndivis; d++)
|
|
_divisp[d]->update (n, m);
|
|
}
|
|
}
|
|
|
|
for (int d = 0; d < _ndivis; d++)
|
|
_divisp[d]->update(_keymap);
|
|
|
|
if (fabsf(_revsize - _audiopar [REVSIZE]) > 0.001f) {
|
|
_revsize = _audiopar[REVSIZE];
|
|
for (int j = 0; j < _nasect; j++)
|
|
_asectp[j]->set_size(_revsize);
|
|
}
|
|
int k = nout;
|
|
while (nframes > 0) {
|
|
if (nout == 0) {
|
|
float W [PERIOD];
|
|
float X [PERIOD];
|
|
float Y [PERIOD];
|
|
float R [PERIOD];
|
|
memset(W, 0, PERIOD * sizeof (float));
|
|
memset(X, 0, PERIOD * sizeof (float));
|
|
memset(Y, 0, PERIOD * sizeof (float));
|
|
memset(R, 0, PERIOD * sizeof (float));
|
|
|
|
for (int j = 0; j < _ndivis; j++)
|
|
_divisp[j]->process();
|
|
for (int j = 0; j < _nasect; j++)
|
|
_asectp[j]->process(gain, W, X, Y, R);
|
|
|
|
float stposit = _audiopar[STPOSIT];
|
|
for (int j = 0; j < PERIOD; j++) {
|
|
loutb[j] = W[j] + stposit * X[j] + Y[j];
|
|
routb[j] = W[j] + stposit * X[j] - Y[j];
|
|
}
|
|
nout = PERIOD;
|
|
k += PERIOD;
|
|
}
|
|
*out++ += gain * loutb[PERIOD - nout];
|
|
*out++ += gain * routb[PERIOD - nout];
|
|
--nout;
|
|
--nframes;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// newDivis
|
|
//---------------------------------------------------------
|
|
|
|
void Aeolus::newDivis(M_new_divis* X)
|
|
{
|
|
Division *D = new Division (_asectp [X->_asect], (float) _fsamp);
|
|
D->set_div_mask (X->_dmask);
|
|
D->set_swell (X->_swell);
|
|
D->set_tfreq (X->_tfreq);
|
|
D->set_tmodd (X->_tmodd);
|
|
_divisp [_ndivis] = D;
|
|
_ndivis++;
|
|
}
|
|
|
|
void Aeolus::cond_key_off (int m, int b)
|
|
{
|
|
unsigned char* p = _keymap;
|
|
|
|
for (int i = 0; i < NNOTES; i++, p++) {
|
|
if (*p & m) {
|
|
*p &= ~b;
|
|
*p |= 0x80;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aeolus::cond_key_on (int m, int b)
|
|
{
|
|
unsigned char* p = _keymap;
|
|
|
|
for (int i = 0; i < NNOTES; i++, p++) {
|
|
if (*p & m)
|
|
*p |= b | 0x80;
|
|
}
|
|
}
|
|
|
|
void Aeolus::key_off (int n, int b)
|
|
{
|
|
_keymap[n] &= ~b;
|
|
_keymap[n] |= 0x80;
|
|
}
|
|
|
|
void Aeolus::key_on (int n, int b)
|
|
{
|
|
_keymap[n] |= b | 0x80;
|
|
}
|
|
|
|
|