mirror of https://github.com/dcoredump/dexed.git
parent
77fa26a066
commit
05cd3aeba9
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,257 +1,272 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
#ifdef VERBOSE |
#ifdef VERBOSE |
||||||
#include <iostream> |
#include <iostream> |
||||||
#endif |
using namespace std; |
||||||
#include <math.h> |
#endif |
||||||
#include "synth.h" |
#include <math.h> |
||||||
#include "freqlut.h" |
#include "synth.h" |
||||||
#include "exp2.h" |
#include "freqlut.h" |
||||||
#include "controllers.h" |
#include "exp2.h" |
||||||
#include "dx7note.h" |
#include "controllers.h" |
||||||
|
#include "dx7note.h" |
||||||
using namespace std; |
|
||||||
|
void dexed_trace(const char *source, const char *fmt, ...); |
||||||
void dexed_trace(const char *source, const char *fmt, ...); |
|
||||||
|
#ifdef _MSC_VER |
||||||
#ifdef _MSC_VER |
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__) |
||||||
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__) |
#else |
||||||
#else |
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__) |
||||||
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__) |
#endif |
||||||
#endif |
|
||||||
|
int32_t midinote_to_logfreq(int midinote) { |
||||||
int32_t midinote_to_logfreq(int midinote) { |
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
|
||||||
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
|
const int step = (1 << 24) / 12; |
||||||
const int step = (1 << 24) / 12; |
return base + step * midinote; |
||||||
return base + step * midinote; |
} |
||||||
} |
|
||||||
|
const int32_t coarsemul[] = { |
||||||
const int32_t coarsemul[] = { |
-16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600, |
||||||
-16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600, |
50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816, |
||||||
50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816, |
65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858, |
||||||
65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858, |
74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032, |
||||||
74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032, |
81503396, 82323963, 83117622 |
||||||
81503396, 82323963, 83117622 |
}; |
||||||
}; |
|
||||||
|
int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { |
||||||
int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { |
// TODO: pitch randomization
|
||||||
// TODO: pitch randomization
|
int32_t logfreq; |
||||||
int32_t logfreq; |
if (mode == 0) { |
||||||
if (mode == 0) { |
logfreq = midinote_to_logfreq(midinote); |
||||||
logfreq = midinote_to_logfreq(midinote); |
logfreq += coarsemul[coarse & 31]; |
||||||
logfreq += coarsemul[coarse & 31]; |
if (fine) { |
||||||
if (fine) { |
// (1 << 24) / log(2)
|
||||||
// (1 << 24) / log(2)
|
logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); |
||||||
logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); |
} |
||||||
} |
// This was measured at 7.213Hz per count at 9600Hz, but the exact
|
||||||
// This was measured at 7.213Hz per count at 9600Hz, but the exact
|
// value is somewhat dependent on midinote. Close enough for now.
|
||||||
// value is somewhat dependent on midinote. Close enough for now.
|
logfreq += 12606 * (detune - 7); |
||||||
logfreq += 12606 * (detune - 7); |
} else { |
||||||
} else { |
// ((1 << 24) * log(10) / log(2) * .01) << 3
|
||||||
// ((1 << 24) * log(10) / log(2) * .01) << 3
|
logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; |
||||||
logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; |
logfreq += detune > 7 ? 13457 * (detune - 7) : 0; |
||||||
logfreq += detune > 7 ? 13457 * (detune - 7) : 0; |
} |
||||||
} |
return logfreq; |
||||||
return logfreq; |
} |
||||||
} |
|
||||||
|
const uint8_t velocity_data[64] = { |
||||||
const uint8_t velocity_data[64] = { |
0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163, |
||||||
0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163, |
166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202, |
||||||
166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202, |
205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232, |
||||||
205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232, |
233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251, |
||||||
233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251, |
252, 253, 254 |
||||||
252, 253, 254 |
}; |
||||||
}; |
|
||||||
|
// See "velocity" section of notes. Returns velocity delta in microsteps.
|
||||||
// See "velocity" section of notes. Returns velocity delta in microsteps.
|
int ScaleVelocity(int velocity, int sensitivity) { |
||||||
int ScaleVelocity(int velocity, int sensitivity) { |
int clamped_vel = max(0, min(127, velocity)); |
||||||
int clamped_vel = max(0, min(127, velocity)); |
int vel_value = velocity_data[clamped_vel >> 1] - 239; |
||||||
int vel_value = velocity_data[clamped_vel >> 1] - 239; |
int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4; |
||||||
int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4; |
return scaled_vel; |
||||||
return scaled_vel; |
} |
||||||
} |
|
||||||
|
int ScaleRate(int midinote, int sensitivity) { |
||||||
int ScaleRate(int midinote, int sensitivity) { |
int x = min(31, max(0, midinote / 3 - 7)); |
||||||
int x = min(31, max(0, midinote / 3 - 7)); |
int qratedelta = (sensitivity * x) >> 3; |
||||||
int qratedelta = (sensitivity * x) >> 3; |
#ifdef SUPER_PRECISE |
||||||
#ifdef SUPER_PRECISE |
int rem = x & 7; |
||||||
int rem = x & 7; |
if (sensitivity == 3 && rem == 3) { |
||||||
if (sensitivity == 3 && rem == 3) { |
qratedelta -= 1; |
||||||
qratedelta -= 1; |
} else if (sensitivity == 7 && rem > 0 && rem < 4) { |
||||||
} else if (sensitivity == 7 && rem > 0 && rem < 4) { |
qratedelta += 1; |
||||||
qratedelta += 1; |
} |
||||||
} |
#endif |
||||||
#endif |
return qratedelta; |
||||||
return qratedelta; |
} |
||||||
} |
|
||||||
|
const uint8_t exp_scale_data[] = { |
||||||
const uint8_t exp_scale_data[] = { |
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66, |
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66, |
80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250 |
||||||
80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250 |
}; |
||||||
}; |
|
||||||
|
int ScaleCurve(int group, int depth, int curve) { |
||||||
int ScaleCurve(int group, int depth, int curve) { |
int scale; |
||||||
int scale; |
if (curve == 0 || curve == 3) { |
||||||
if (curve == 0 || curve == 3) { |
// linear
|
||||||
// linear
|
scale = (group * depth * 329) >> 12; |
||||||
scale = (group * depth * 329) >> 12; |
} else { |
||||||
} else { |
// exponential
|
||||||
// exponential
|
int n_scale_data = sizeof(exp_scale_data); |
||||||
int n_scale_data = sizeof(exp_scale_data); |
int raw_exp = exp_scale_data[min(group, n_scale_data - 1)]; |
||||||
int raw_exp = exp_scale_data[min(group, n_scale_data - 1)]; |
scale = (raw_exp * depth * 329) >> 15; |
||||||
scale = (raw_exp * depth * 329) >> 15; |
} |
||||||
} |
if (curve < 2) { |
||||||
if (curve < 2) { |
scale = -scale; |
||||||
scale = -scale; |
} |
||||||
} |
return scale; |
||||||
return scale; |
} |
||||||
} |
|
||||||
|
int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, |
||||||
int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, |
int left_curve, int right_curve) { |
||||||
int left_curve, int right_curve) { |
int offset = midinote - break_pt - 17; |
||||||
int offset = midinote - break_pt - 17; |
if (offset >= 0) { |
||||||
if (offset >= 0) { |
return ScaleCurve(offset / 3, right_depth, right_curve); |
||||||
return ScaleCurve(offset / 3, right_depth, right_curve); |
} else { |
||||||
} else { |
return ScaleCurve((-offset) / 3, left_depth, left_curve); |
||||||
return ScaleCurve((-offset) / 3, left_depth, left_curve); |
} |
||||||
} |
} |
||||||
} |
|
||||||
|
static const uint8_t pitchmodsenstab[] = { |
||||||
static const uint8_t pitchmodsenstab[] = { |
0, 10, 20, 33, 55, 92, 153, 255 |
||||||
0, 10, 20, 33, 55, 92, 153, 255 |
}; |
||||||
}; |
|
||||||
|
// PG: we need to find the real values
|
||||||
void Dx7Note::init(const char patch[156], int midinote, int velocity) { |
static const uint8_t ampmodsenstab[] = { |
||||||
int rates[4]; |
0, 33, 153, 255 |
||||||
int levels[4]; |
}; |
||||||
for (int op = 0; op < 6; op++) { |
|
||||||
int off = op * 21; |
void Dx7Note::init(const char patch[156], int midinote, int velocity) { |
||||||
for (int i = 0; i < 4; i++) { |
int rates[4]; |
||||||
rates[i] = patch[off + i]; |
int levels[4]; |
||||||
levels[i] = patch[off + 4 + i]; |
for (int op = 0; op < 6; op++) { |
||||||
} |
int off = op * 21; |
||||||
int outlevel = patch[off + 16]; |
for (int i = 0; i < 4; i++) { |
||||||
outlevel = Env::scaleoutlevel(outlevel); |
rates[i] = patch[off + i]; |
||||||
#ifdef VERBOSE |
levels[i] = patch[off + 4 + i]; |
||||||
for (int j = 8; j < 12; j++) { |
} |
||||||
cout << (int)patch[off + j] << " "; |
int outlevel = patch[off + 16]; |
||||||
} |
outlevel = Env::scaleoutlevel(outlevel); |
||||||
#endif |
#ifdef VERBOSE |
||||||
int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], |
for (int j = 8; j < 12; j++) { |
||||||
patch[off + 10], patch[off + 11], patch[off + 12]); |
cout << (int)patch[off + j] << " "; |
||||||
outlevel += level_scaling; |
} |
||||||
outlevel = min(127, outlevel); |
#endif |
||||||
#ifdef VERBOSE |
int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], |
||||||
cout << op << ": " << level_scaling << " " << outlevel << endl; |
patch[off + 10], patch[off + 11], patch[off + 12]); |
||||||
#endif |
outlevel += level_scaling; |
||||||
outlevel = outlevel << 5; |
outlevel = min(127, outlevel); |
||||||
outlevel += ScaleVelocity(velocity, patch[off + 15]); |
#ifdef VERBOSE |
||||||
outlevel = max(0, outlevel); |
cout << op << ": " << level_scaling << " " << outlevel << endl; |
||||||
int rate_scaling = ScaleRate(midinote, patch[off + 13]); |
#endif |
||||||
env_[op].init(rates, levels, outlevel, rate_scaling); |
outlevel = outlevel << 5; |
||||||
|
outlevel += ScaleVelocity(velocity, patch[off + 15]); |
||||||
int mode = patch[off + 17]; |
outlevel = max(0, outlevel); |
||||||
int coarse = patch[off + 18]; |
int rate_scaling = ScaleRate(midinote, patch[off + 13]); |
||||||
int fine = patch[off + 19]; |
env_[op].init(rates, levels, outlevel, rate_scaling); |
||||||
int detune = patch[off + 20]; |
|
||||||
int32_t freq = osc_freq(midinote, mode, coarse, fine, detune); |
int mode = patch[off + 17]; |
||||||
basepitch_[op] = freq; |
int coarse = patch[off + 18]; |
||||||
// cout << op << " freq: " << freq << endl;
|
int fine = patch[off + 19]; |
||||||
params_[op].phase = 0; |
int detune = patch[off + 20]; |
||||||
params_[op].gain[1] = 0; |
int32_t freq = osc_freq(midinote, mode, coarse, fine, detune); |
||||||
} |
basepitch_[op] = freq; |
||||||
for (int i = 0; i < 4; i++) { |
// cout << op << " freq: " << freq << endl;
|
||||||
rates[i] = patch[126 + i]; |
params_[op].phase = 0; |
||||||
levels[i] = patch[130 + i]; |
params_[op].gain[1] = 0; |
||||||
} |
ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; |
||||||
pitchenv_.set(rates, levels); |
|
||||||
algorithm_ = patch[134]; |
TRACE("operator set: %d %d", op, ampmodsens_[op]); |
||||||
int feedback = patch[135]; |
} |
||||||
fb_shift_ = feedback != 0 ? 8 - feedback : 16; |
for (int i = 0; i < 4; i++) { |
||||||
pitchmoddepth_ = (patch[139] * 165) >> 6; |
rates[i] = patch[126 + i]; |
||||||
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; |
levels[i] = patch[130 + i]; |
||||||
ampmoddepth_ = (patch[140] * 165) >> 6; |
} |
||||||
} |
pitchenv_.set(rates, levels); |
||||||
|
algorithm_ = patch[134]; |
||||||
void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, |
int feedback = patch[135]; |
||||||
const Controllers *ctrls) { |
fb_shift_ = feedback != 0 ? 8 - feedback : 16; |
||||||
int32_t pitchmod = pitchenv_.getsample(); |
pitchmoddepth_ = (patch[139] * 165) >> 6; |
||||||
uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32
|
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; |
||||||
// TODO: add modulation sources (mod wheel, etc)
|
ampmoddepth_ = (patch[140] * 165) >> 6; |
||||||
uint32_t pwmd = (ctrls->values_[kControllerModWheel] * 0.7874) * (1 << 24); |
} |
||||||
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); |
|
||||||
|
void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, |
||||||
pitchmod += (((int64_t)pwmd) * (int64_t)senslfo) >> 39; |
const Controllers *ctrls) { |
||||||
pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39; |
int32_t pitchmod = pitchenv_.getsample(); |
||||||
|
uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32
|
||||||
int pitchbend = ctrls->values_[kControllerPitch]; |
// TODO(PG) : make this integer friendly
|
||||||
int32_t pb = (pitchbend - 0x2000); |
uint32_t pwmd = (ctrls->values_[kControllerModWheel] * 0.7874) * (1 << 24); |
||||||
|
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); |
||||||
if ( pb != 0 ) { |
uint32_t amd = ampmoddepth_ * lfo_delay; // Q32 :D
|
||||||
if ( ctrls->values_[kControllerPitchStep] == 0 ) { |
|
||||||
pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0; |
pitchmod += (((int64_t)pwmd) * (int64_t)senslfo) >> 39; |
||||||
} else { |
pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39; |
||||||
int stp = 12 / ctrls->values_[kControllerPitchStep]; |
|
||||||
pb = pb * stp / 8191; |
int pitchbend = ctrls->values_[kControllerPitch]; |
||||||
pb = (pb * (8191/stp)) << 11; |
int32_t pb = (pitchbend - 0x2000); |
||||||
} |
|
||||||
} |
if ( pb != 0 ) { |
||||||
|
if ( ctrls->values_[kControllerPitchStep] == 0 ) { |
||||||
pitchmod += pb; |
pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0; |
||||||
for (int op = 0; op < 6; op++) { |
} else { |
||||||
params_[op].gain[0] = params_[op].gain[1]; |
int stp = 12 / ctrls->values_[kControllerPitchStep]; |
||||||
int32_t level = env_[op].getsample(); |
pb = pb * stp / 8191; |
||||||
int32_t gain = Exp2::lookup(level - (14 * (1 << 24))); |
pb = (pb * (8191/stp)) << 11; |
||||||
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
|
} |
||||||
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod); |
} |
||||||
params_[op].gain[1] = gain; |
|
||||||
} |
pitchmod += pb; |
||||||
core_.compute(buf, params_, algorithm_, fb_buf_, fb_shift_); |
for (int op = 0; op < 6; op++) { |
||||||
} |
params_[op].gain[0] = params_[op].gain[1]; |
||||||
|
|
||||||
void Dx7Note::keyup() { |
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
|
||||||
for (int op = 0; op < 6; op++) { |
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod); |
||||||
env_[op].keydown(false); |
|
||||||
pitchenv_.keydown(false); |
int32_t level = env_[op].getsample(); |
||||||
} |
if ( ampmodsens_[op] != 0 ) { |
||||||
} |
uint32_t sensamp = ampmodsens_[op] * (lfo_val - (1 << 23)); |
||||||
|
uint32_t amd_level = (((int64_t)amd) * (int64_t)sensamp) >> 40; |
||||||
void Dx7Note::update(const char patch[156], int midinote) { |
level -= amd_level; |
||||||
for (int op = 0; op < 6; op++) { |
} |
||||||
int off = op * 21; |
int32_t gain = Exp2::lookup(level - (14 * (1 << 24))); |
||||||
int mode = patch[off + 17]; |
params_[op].gain[1] = gain; |
||||||
int coarse = patch[off + 18]; |
} |
||||||
int fine = patch[off + 19]; |
core_.compute(buf, params_, algorithm_, fb_buf_, fb_shift_, ctrls); |
||||||
int detune = patch[off + 20]; |
} |
||||||
basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune); |
|
||||||
} |
void Dx7Note::keyup() { |
||||||
algorithm_ = patch[134]; |
for (int op = 0; op < 6; op++) { |
||||||
int feedback = patch[135]; |
env_[op].keydown(false); |
||||||
fb_shift_ = feedback != 0 ? 8 - feedback : 16; |
pitchenv_.keydown(false); |
||||||
pitchmoddepth_ = (patch[139] * 165) >> 6; |
} |
||||||
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; |
} |
||||||
} |
|
||||||
|
void Dx7Note::update(const char patch[156], int midinote) { |
||||||
void Dx7Note::peekVoiceStatus(VoiceStatus &status) { |
for (int op = 0; op < 6; op++) { |
||||||
for(int i=0;i<6;i++) { |
int off = op * 21; |
||||||
status.amp[i] = params_[i].gain[1]; |
int mode = patch[off + 17]; |
||||||
env_[i].getPosition(&status.ampStep[i]); |
int coarse = patch[off + 18]; |
||||||
} |
int fine = patch[off + 19]; |
||||||
pitchenv_.getPosition(&status.pitchStep); |
int detune = patch[off + 20]; |
||||||
} |
basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune); |
||||||
|
} |
||||||
|
algorithm_ = patch[134]; |
||||||
|
int feedback = patch[135]; |
||||||
|
fb_shift_ = feedback != 0 ? 8 - feedback : 16; |
||||||
|
pitchmoddepth_ = (patch[139] * 165) >> 6; |
||||||
|
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; |
||||||
|
} |
||||||
|
|
||||||
|
void Dx7Note::peekVoiceStatus(VoiceStatus &status) { |
||||||
|
for(int i=0;i<6;i++) { |
||||||
|
status.amp[i] = params_[i].gain[1]; |
||||||
|
env_[i].getPosition(&status.ampStep[i]); |
||||||
|
} |
||||||
|
pitchenv_.getPosition(&status.pitchStep); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@ -1,73 +1,74 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
#ifndef SYNTH_DX7NOTE_H_ |
#ifndef SYNTH_DX7NOTE_H_ |
||||||
#define SYNTH_DX7NOTE_H_ |
#define SYNTH_DX7NOTE_H_ |
||||||
|
|
||||||
// This is the logic to put together a note from the MIDI description
|
// This is the logic to put together a note from the MIDI description
|
||||||
// and run the low-level modules.
|
// and run the low-level modules.
|
||||||
|
|
||||||
// It will continue to evolve a bit, as note-stealing logic, scaling,
|
// It will continue to evolve a bit, as note-stealing logic, scaling,
|
||||||
// and real-time control of parameters live here.
|
// and real-time control of parameters live here.
|
||||||
|
|
||||||
#include "env.h" |
#include "env.h" |
||||||
#include "pitchenv.h" |
#include "pitchenv.h" |
||||||
#include "fm_core.h" |
#include "fm_core.h" |
||||||
|
|
||||||
struct VoiceStatus { |
struct VoiceStatus { |
||||||
uint32_t amp[6]; |
uint32_t amp[6]; |
||||||
char ampStep[6]; |
char ampStep[6]; |
||||||
char pitchStep; |
char pitchStep; |
||||||
}; |
}; |
||||||
|
|
||||||
class Dx7Note { |
class Dx7Note { |
||||||
public: |
public: |
||||||
void init(const char patch[156], int midinote, int velocity); |
void init(const char patch[156], int midinote, int velocity); |
||||||
|
|
||||||
// Note: this _adds_ to the buffer. Interesting question whether it's
|
// Note: this _adds_ to the buffer. Interesting question whether it's
|
||||||
// worth it...
|
// worth it...
|
||||||
void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, |
void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, |
||||||
const Controllers *ctrls); |
const Controllers *ctrls); |
||||||
|
|
||||||
void keyup(); |
void keyup(); |
||||||
|
|
||||||
// TODO: parameter changes
|
// TODO: parameter changes
|
||||||
|
|
||||||
// TODO: some way of indicating end-of-note. Maybe should be a return
|
// TODO: some way of indicating end-of-note. Maybe should be a return
|
||||||
// value from the compute method? (Having a count return from keyup
|
// value from the compute method? (Having a count return from keyup
|
||||||
// is also tempting, but if there's a dynamic parameter change after
|
// is also tempting, but if there's a dynamic parameter change after
|
||||||
// keyup, that won't work.
|
// keyup, that won't work.
|
||||||
|
|
||||||
// PG:add the update
|
// PG:add the update
|
||||||
void update(const char patch[156], int midinote); |
void update(const char patch[156], int midinote); |
||||||
void peekVoiceStatus(VoiceStatus &status); |
void peekVoiceStatus(VoiceStatus &status);
|
||||||
|
|
||||||
private: |
private: |
||||||
FmCore core_; |
FmCore core_; |
||||||
Env env_[6]; |
Env env_[6]; |
||||||
FmOpParams params_[6]; |
FmOpParams params_[6]; |
||||||
PitchEnv pitchenv_; |
PitchEnv pitchenv_; |
||||||
int32_t basepitch_[6]; |
int32_t basepitch_[6]; |
||||||
int32_t fb_buf_[2]; |
int32_t fb_buf_[2]; |
||||||
int32_t fb_shift_; |
int32_t fb_shift_; |
||||||
|
int32_t ampmodsens_[6]; |
||||||
int ampmoddepth_; |
|
||||||
int algorithm_; |
int ampmoddepth_; |
||||||
int pitchmoddepth_; |
int algorithm_; |
||||||
int pitchmodsens_; |
int pitchmoddepth_; |
||||||
}; |
int pitchmodsens_; |
||||||
|
}; |
||||||
#endif // SYNTH_DX7NOTE_H_
|
|
||||||
|
#endif // SYNTH_DX7NOTE_H_
|
||||||
|
@ -1,151 +1,152 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
#ifdef VERBOSE |
#ifdef VERBOSE |
||||||
#include <iostream> |
#include <iostream> |
||||||
#endif |
#endif |
||||||
|
|
||||||
#include "synth.h" |
#include "synth.h" |
||||||
#include "fm_op_kernel.h" |
#include "fm_op_kernel.h" |
||||||
#include "fm_core.h" |
#include "fm_core.h" |
||||||
|
|
||||||
using namespace std; |
|
||||||
|
using namespace std; |
||||||
struct FmOperatorInfo { |
|
||||||
int in; |
struct FmOperatorInfo { |
||||||
int out; |
int in; |
||||||
}; |
int out; |
||||||
|
}; |
||||||
enum FmOperatorFlags { |
|
||||||
OUT_BUS_ONE = 1 << 0, |
enum FmOperatorFlags { |
||||||
OUT_BUS_TWO = 1 << 1, |
OUT_BUS_ONE = 1 << 0, |
||||||
OUT_BUS_ADD = 1 << 2, |
OUT_BUS_TWO = 1 << 1, |
||||||
IN_BUS_ONE = 1 << 4, |
OUT_BUS_ADD = 1 << 2, |
||||||
IN_BUS_TWO = 1 << 5, |
IN_BUS_ONE = 1 << 4, |
||||||
FB_IN = 1 << 6, |
IN_BUS_TWO = 1 << 5, |
||||||
FB_OUT = 1 << 7 |
FB_IN = 1 << 6, |
||||||
}; |
FB_OUT = 1 << 7 |
||||||
|
}; |
||||||
struct FmAlgorithm { |
|
||||||
int ops[6]; |
struct FmAlgorithm { |
||||||
}; |
int ops[6]; |
||||||
|
}; |
||||||
const FmAlgorithm algorithms[32] = { |
|
||||||
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
|
const FmAlgorithm algorithms[32] = { |
||||||
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
|
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
|
||||||
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
|
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
|
||||||
{ { 0x41, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4
|
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
|
||||||
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
|
{ { 0x41, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4
|
||||||
{ { 0x41, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6
|
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
|
||||||
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
|
{ { 0x41, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6
|
||||||
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
|
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
|
||||||
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
|
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
|
||||||
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
|
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
|
||||||
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
|
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
|
||||||
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
|
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
|
||||||
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
|
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
|
||||||
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
|
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
|
||||||
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
|
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
|
||||||
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
|
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
|
||||||
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
|
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
|
||||||
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
|
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
|
||||||
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
|
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
|
||||||
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
|
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
|
||||||
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
|
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
|
||||||
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
|
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
|
||||||
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
|
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
|
||||||
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
|
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
|
||||||
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
|
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
|
||||||
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
|
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
|
||||||
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
|
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
|
||||||
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
|
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
|
||||||
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
|
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
|
||||||
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
|
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
|
||||||
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
|
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
|
||||||
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
|
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
|
||||||
}; |
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
|
||||||
|
}; |
||||||
int n_out(const FmAlgorithm &alg) { |
|
||||||
int count = 0; |
int n_out(const FmAlgorithm &alg) { |
||||||
for (int i = 0; i < 6; i++) { |
int count = 0; |
||||||
if ((alg.ops[i] & 7) == OUT_BUS_ADD) count++; |
for (int i = 0; i < 6; i++) { |
||||||
} |
if ((alg.ops[i] & 7) == OUT_BUS_ADD) count++; |
||||||
return count; |
} |
||||||
} |
return count; |
||||||
|
} |
||||||
void FmCore::dump() { |
|
||||||
#ifdef VERBOSE |
void FmCore::dump() { |
||||||
for (int i = 0; i < 32; i++) { |
#ifdef VERBOSE |
||||||
cout << (i + 1) << ":"; |
for (int i = 0; i < 32; i++) { |
||||||
const FmAlgorithm &alg = algorithms[i]; |
cout << (i + 1) << ":"; |
||||||
for (int j = 0; j < 6; j++) { |
const FmAlgorithm &alg = algorithms[i]; |
||||||
int flags = alg.ops[j]; |
for (int j = 0; j < 6; j++) { |
||||||
cout << " "; |
int flags = alg.ops[j]; |
||||||
if (flags & FB_IN) cout << "["; |
cout << " "; |
||||||
cout << (flags & IN_BUS_ONE ? "1" : flags & IN_BUS_TWO ? "2" : "0") << "->"; |
if (flags & FB_IN) cout << "["; |
||||||
cout << (flags & OUT_BUS_ONE ? "1" : flags & OUT_BUS_TWO ? "2" : "0"); |
cout << (flags & IN_BUS_ONE ? "1" : flags & IN_BUS_TWO ? "2" : "0") << "->"; |
||||||
if (flags & OUT_BUS_ADD) cout << "+"; |
cout << (flags & OUT_BUS_ONE ? "1" : flags & OUT_BUS_TWO ? "2" : "0"); |
||||||
//cout << alg.ops[j].in << "->" << alg.ops[j].out;
|
if (flags & OUT_BUS_ADD) cout << "+"; |
||||||
if (flags & FB_OUT) cout << "]"; |
//cout << alg.ops[j].in << "->" << alg.ops[j].out;
|
||||||
} |
if (flags & FB_OUT) cout << "]"; |
||||||
cout << " " << n_out(alg); |
} |
||||||
cout << endl; |
cout << " " << n_out(alg); |
||||||
} |
cout << endl; |
||||||
#endif |
} |
||||||
} |
#endif |
||||||
|
} |
||||||
void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, |
|
||||||
int32_t *fb_buf, int feedback_shift) { |
void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, |
||||||
const int kLevelThresh = 1120; |
int32_t *fb_buf, int feedback_shift, const Controllers *controllers) { |
||||||
const FmAlgorithm alg = algorithms[algorithm]; |
const int kLevelThresh = 1120; |
||||||
bool has_contents[3] = { true, false, false }; |
const FmAlgorithm alg = algorithms[algorithm]; |
||||||
for (int op = 0; op < 6; op++) { |
bool has_contents[3] = { true, false, false }; |
||||||
int flags = alg.ops[op]; |
for (int op = 0; op < 6; op++) { |
||||||
bool add = (flags & OUT_BUS_ADD) != 0; |
int flags = alg.ops[op]; |
||||||
FmOpParams ¶m = params[op]; |
bool add = (flags & OUT_BUS_ADD) != 0; |
||||||
int inbus = (flags >> 4) & 3; |
FmOpParams ¶m = params[op]; |
||||||
int outbus = flags & 3; |
int inbus = (flags >> 4) & 3; |
||||||
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); |
int outbus = flags & 3; |
||||||
int32_t gain1 = param.gain[0]; |
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); |
||||||
int32_t gain2 = param.gain[1]; |
int32_t gain1 = param.gain[0]; |
||||||
if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { |
int32_t gain2 = param.gain[1]; |
||||||
if (!has_contents[outbus]) { |
if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { |
||||||
add = false; |
if (!has_contents[outbus]) { |
||||||
} |
add = false; |
||||||
if (inbus == 0 || !has_contents[inbus]) { |
} |
||||||
// todo: more than one op in a feedback loop
|
if (inbus == 0 || !has_contents[inbus]) { |
||||||
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { |
// todo: more than one op in a feedback loop
|
||||||
// cout << op << " fb " << inbus << outbus << add << endl;
|
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { |
||||||
FmOpKernel::compute_fb(outptr, param.phase, param.freq, |
// cout << op << " fb " << inbus << outbus << add << endl;
|
||||||
gain1, gain2, |
FmOpKernel::compute_fb(outptr, param.phase, param.freq, |
||||||
fb_buf, feedback_shift, add); |
gain1, gain2, |
||||||
} else { |
fb_buf, feedback_shift, add, controllers); |
||||||
// cout << op << " pure " << inbus << outbus << add << endl;
|
} else { |
||||||
FmOpKernel::compute_pure(outptr, param.phase, param.freq, |
// cout << op << " pure " << inbus << outbus << add << endl;
|
||||||
gain1, gain2, add); |
FmOpKernel::compute_pure(outptr, param.phase, param.freq, |
||||||
} |
gain1, gain2, add, controllers); |
||||||
} else { |
} |
||||||
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
|
} else { |
||||||
FmOpKernel::compute(outptr, buf_[inbus - 1].get(), |
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
|
||||||
param.phase, param.freq, gain1, gain2, add); |
FmOpKernel::compute(outptr, buf_[inbus - 1].get(), |
||||||
} |
param.phase, param.freq, gain1, gain2, add, controllers); |
||||||
has_contents[outbus] = true; |
} |
||||||
} else if (!add) { |
has_contents[outbus] = true; |
||||||
has_contents[outbus] = false; |
} else if (!add) { |
||||||
} |
has_contents[outbus] = false; |
||||||
param.phase += param.freq << LG_N; |
} |
||||||
} |
param.phase += param.freq << LG_N; |
||||||
} |
} |
||||||
|
} |
@ -1,38 +1,40 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
#ifndef __FM_CORE_H |
#ifndef __FM_CORE_H |
||||||
#define __FM_CORE_H |
#define __FM_CORE_H |
||||||
|
|
||||||
#include "aligned_buf.h" |
#include "aligned_buf.h" |
||||||
#include "synth.h" |
#include "fm_op_kernel.h" |
||||||
|
#include "synth.h" |
||||||
struct FmOpParams { |
#include "controllers.h" |
||||||
int32_t gain[2]; |
|
||||||
int32_t freq; |
struct FmOpParams { |
||||||
int32_t phase; |
int32_t gain[2]; |
||||||
}; |
int32_t freq; |
||||||
|
int32_t phase; |
||||||
class FmCore { |
}; |
||||||
public: |
|
||||||
static void dump(); |
class FmCore { |
||||||
void compute(int32_t *output, FmOpParams *params, int algorithm, |
public: |
||||||
int32_t *fb_buf, int32_t feedback_gain); |
static void dump(); |
||||||
private: |
void compute(int32_t *output, FmOpParams *params, int algorithm, |
||||||
AlignedBuf<int32_t, N>buf_[2]; |
int32_t *fb_buf, int32_t feedback_gain, const Controllers *controller); |
||||||
}; |
private: |
||||||
|
AlignedBuf<int32_t, N>buf_[2]; |
||||||
#endif // __FM_CORE_H
|
}; |
||||||
|
|
||||||
|
#endif // __FM_CORE_H
|
||||||
|
@ -1,274 +1,299 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
#include <math.h> |
#include <math.h> |
||||||
|
|
||||||
#ifdef HAVE_NEON |
#include <cstdlib> |
||||||
#include <cpu-features.h> |
|
||||||
#endif |
#ifdef HAVE_NEON |
||||||
|
#include <cpu-features.h> |
||||||
#include "synth.h" |
#endif |
||||||
|
|
||||||
#include "sin.h" |
#include "synth.h" |
||||||
#include "fm_op_kernel.h" |
|
||||||
|
#include "sin.h" |
||||||
#ifdef HAVE_NEON |
#include "fm_op_kernel.h" |
||||||
static bool hasNeon() { |
|
||||||
return true; |
|
||||||
return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
uint32_t restdither() { |
||||||
} |
return rand() & 0x3FFF; |
||||||
|
return 0; |
||||||
extern "C" |
|
||||||
void neon_fm_kernel(const int *in, const int *busin, int *out, int count, |
} |
||||||
int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain); |
|
||||||
|
#ifdef HAVE_NEONx |
||||||
const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; |
static bool hasNeon() { |
||||||
|
return true; |
||||||
#else |
return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
||||||
static bool hasNeon() { |
} |
||||||
return false; |
|
||||||
} |
extern "C" |
||||||
#endif |
void neon_fm_kernel(const int *in, const int *busin, int *out, int count, |
||||||
|
int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain); |
||||||
void FmOpKernel::compute(int32_t *output, const int32_t *input, |
|
||||||
int32_t phase0, int32_t freq, |
const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; |
||||||
int32_t gain1, int32_t gain2, bool add) { |
|
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
#else |
||||||
int32_t gain = gain1; |
static bool hasNeon() { |
||||||
int32_t phase = phase0; |
return false; |
||||||
if (hasNeon()) { |
} |
||||||
#ifdef HAVE_NEON |
#endif |
||||||
neon_fm_kernel(input, add ? output : zeros, output, N, |
|
||||||
phase0, freq, gain, dgain); |
//#define BIT8 0xFFFFFF00
|
||||||
#endif |
|
||||||
} else { |
void FmOpKernel::compute(int32_t *output, const int32_t *input, |
||||||
if (add) { |
int32_t phase0, int32_t freq, |
||||||
for (int i = 0; i < N; i++) { |
int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) { |
||||||
gain += dgain; |
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
int32_t y = Sin::lookup(phase + input[i]); |
int32_t gain = gain1; |
||||||
output[i] += ((int64_t)y * (int64_t)gain) >> 24; |
int32_t phase = phase0; |
||||||
phase += freq; |
if (hasNeon()) { |
||||||
} |
#ifdef HAVE_NEON |
||||||
} else { |
neon_fm_kernel(input, add ? output : zeros, output, N, |
||||||
for (int i = 0; i < N; i++) { |
phase0, freq, gain, dgain); |
||||||
gain += dgain; |
#endif |
||||||
int32_t y = Sin::lookup(phase + input[i]); |
} else { |
||||||
output[i] = ((int64_t)y * (int64_t)gain) >> 24; |
if (add) { |
||||||
phase += freq; |
for (int i = 0; i < N; i++) { |
||||||
} |
gain += dgain; |
||||||
} |
int32_t y = Sin::lookup(phase + input[i]); |
||||||
} |
y &= controllers->sinBitFilter; |
||||||
} |
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||||
|
output[i] += y1; |
||||||
#if 1 |
phase += freq; |
||||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
} |
||||||
int32_t gain1, int32_t gain2, bool add) { |
} else { |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
for (int i = 0; i < N; i++) { |
||||||
int32_t gain = gain1; |
gain += dgain; |
||||||
int32_t phase = phase0; |
int32_t y = Sin::lookup(phase + input[i]); |
||||||
if (hasNeon()) { |
y &= controllers->sinBitFilter; |
||||||
#ifdef HAVE_NEON |
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||||
neon_fm_kernel(zeros, add ? output : zeros, output, N, |
output[i] = y1; |
||||||
phase0, freq, gain, dgain); |
phase += freq; |
||||||
#endif |
} |
||||||
} else { |
} |
||||||
if (add) { |
} |
||||||
for (int i = 0; i < N; i++) { |
} |
||||||
gain += dgain; |
|
||||||
int32_t y = Sin::lookup(phase); |
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
output[i] += ((int64_t)y * (int64_t)gain) >> 24; |
int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) { |
||||||
phase += freq; |
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
} |
int32_t gain = gain1; |
||||||
} else { |
int32_t phase = phase0; |
||||||
for (int i = 0; i < N; i++) { |
if (hasNeon()) { |
||||||
gain += dgain; |
#ifdef HAVE_NEON |
||||||
int32_t y = Sin::lookup(phase); |
neon_fm_kernel(zeros, add ? output : zeros, output, N, |
||||||
output[i] = ((int64_t)y * (int64_t)gain) >> 24; |
phase0, freq, gain, dgain); |
||||||
phase += freq; |
#endif |
||||||
} |
} else { |
||||||
} |
if (add) { |
||||||
} |
for (int i = 0; i < N; i++) { |
||||||
} |
gain += dgain; |
||||||
#endif |
int32_t y = Sin::lookup(phase); |
||||||
|
y &= controllers->sinBitFilter; |
||||||
#define noDOUBLE_ACCURACY |
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||||
#define HIGH_ACCURACY |
output[i] += y1; |
||||||
|
phase += freq; |
||||||
// Experimental sine wave generators below
|
} |
||||||
#if 0 |
} else { |
||||||
// Results: accuracy 64.3 mean, 170 worst case
|
for (int i = 0; i < N; i++) { |
||||||
// high accuracy: 5.0 mean, 49 worst case
|
gain += dgain; |
||||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
int32_t y = Sin::lookup(phase); |
||||||
int32_t gain1, int32_t gain2, bool add) { |
y &= controllers->sinBitFilter; |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
|
||||||
int32_t gain = gain1; |
output[i] = y1; |
||||||
int32_t phase = phase0; |
phase += freq; |
||||||
#ifdef HIGH_ACCURACY |
} |
||||||
int32_t u = Sin::compute10(phase << 6); |
} |
||||||
u = ((int64_t)u * gain) >> 30; |
} |
||||||
int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle
|
} |
||||||
v = ((int64_t)v * gain) >> 30; |
|
||||||
int32_t s = Sin::compute10(freq << 6); |
#define noDOUBLE_ACCURACY |
||||||
int32_t c = Sin::compute10((freq << 6) + (1 << 28)); |
#define HIGH_ACCURACY |
||||||
#else |
|
||||||
int32_t u = Sin::compute(phase); |
void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq, |
||||||
u = ((int64_t)u * gain) >> 24; |
int32_t gain1, int32_t gain2, |
||||||
int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle
|
int32_t *fb_buf, int fb_shift, bool add, const Controllers *controllers) { |
||||||
v = ((int64_t)v * gain) >> 24; |
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
int32_t s = Sin::compute(freq) << 6; |
int32_t gain = gain1; |
||||||
int32_t c = Sin::compute(freq + (1 << 22)) << 6; |
int32_t phase = phase0; |
||||||
#endif |
int32_t y0 = fb_buf[0]; |
||||||
for (int i = 0; i < N; i++) { |
int32_t y = fb_buf[1]; |
||||||
output[i] = u; |
if (add) { |
||||||
int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; |
for (int i = 0; i < N; i++) { |
||||||
u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30; |
gain += dgain; |
||||||
v = t; |
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
||||||
} |
y0 = y; |
||||||
} |
y = Sin::lookup(phase + scaled_fb); |
||||||
#endif |
y &= controllers->sinBitFilter; |
||||||
|
y = ((int64_t)y * (int64_t)gain) >> 24; |
||||||
#if 0 |
output[i] += y; |
||||||
// Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5)
|
phase += freq; |
||||||
// for freq < 0.25, 275.2 mean, 716 worst
|
} |
||||||
// high accuracy: 57.4 mean, 7559 worst
|
} else { |
||||||
// freq < 0.25: 17.9 mean, 78 worst
|
for (int i = 0; i < N; i++) { |
||||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
gain += dgain; |
||||||
int32_t gain1, int32_t gain2, bool add) { |
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
y0 = y; |
||||||
int32_t gain = gain1; |
y = Sin::lookup(phase + scaled_fb); |
||||||
int32_t phase = phase0; |
y &= controllers->sinBitFilter; |
||||||
#ifdef HIGH_ACCURACY |
y = ((int64_t)y * (int64_t)gain) >> 24; |
||||||
int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); |
output[i] = y; |
||||||
int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5); |
phase += freq; |
||||||
int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5); |
} |
||||||
#else |
} |
||||||
int32_t u = Sin::compute(phase); |
fb_buf[0] = y0; |
||||||
u = ((int64_t)u * gain) >> 24; |
fb_buf[1] = y; |
||||||
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
} |
||||||
v = ((int64_t)v * gain) >> 24; |
|
||||||
int32_t a = Sin::compute(freq >> 1) << 1; |
////////////////////////////////////////////////////////////////////////////////////
|
||||||
#endif |
////////////////////////////////////////////////////////////////////////////////////
|
||||||
for (int i = 0; i < N; i++) { |
////////////////////////////////////////////////////////////////////////////////////
|
||||||
output[i] = u; |
////////////////////////////////////////////////////////////////////////////////////
|
||||||
v -= ((int64_t)a * (int64_t)u) >> 24; |
|
||||||
u += ((int64_t)a * (int64_t)v) >> 24; |
// Experimental sine wave generators below
|
||||||
} |
#if 0 |
||||||
} |
// Results: accuracy 64.3 mean, 170 worst case
|
||||||
#endif |
// high accuracy: 5.0 mean, 49 worst case
|
||||||
|
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
#if 0 |
int32_t gain1, int32_t gain2, bool add) { |
||||||
// Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5)
|
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
// with double accuracy initialization: mean 1.55, worst 58 (near freq = 0)
|
int32_t gain = gain1; |
||||||
// with high accuracy: mean 4.2, worst 292 (near freq = 0.5)
|
int32_t phase = phase0; |
||||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
#ifdef HIGH_ACCURACY |
||||||
int32_t gain1, int32_t gain2, bool add) { |
int32_t u = Sin::compute10(phase << 6); |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
u = ((int64_t)u * gain) >> 30; |
||||||
int32_t gain = gain1; |
int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle
|
||||||
int32_t phase = phase0; |
v = ((int64_t)v * gain) >> 30; |
||||||
#ifdef DOUBLE_ACCURACY |
int32_t s = Sin::compute10(freq << 6); |
||||||
int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); |
int32_t c = Sin::compute10((freq << 6) + (1 << 28)); |
||||||
double a_d = sin(freq * (M_PI / (1 << 24))); |
#else |
||||||
int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * |
int32_t u = Sin::compute(phase); |
||||||
(M_PI / (1 << 23))) + 0.5); |
u = ((int64_t)u * gain) >> 24; |
||||||
int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); |
int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle
|
||||||
#else |
v = ((int64_t)v * gain) >> 24; |
||||||
#ifdef HIGH_ACCURACY |
int32_t s = Sin::compute(freq) << 6; |
||||||
int32_t u = Sin::compute10(phase << 6); |
int32_t c = Sin::compute(freq + (1 << 22)) << 6; |
||||||
int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); |
#endif |
||||||
int32_t a = Sin::compute10(freq << 5); |
for (int i = 0; i < N; i++) { |
||||||
v = ((int64_t)v * (int64_t)a) >> 29; |
output[i] = u; |
||||||
int32_t aa = ((int64_t)a * (int64_t)a) >> 29; |
int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; |
||||||
#else |
u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30; |
||||||
int32_t u = Sin::compute(phase) << 6; |
v = t; |
||||||
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
} |
||||||
int32_t a = Sin::compute(freq >> 1); |
} |
||||||
v = ((int64_t)v * (int64_t)a) >> 17; |
#endif |
||||||
int32_t aa = ((int64_t)a * (int64_t)a) >> 17; |
|
||||||
#endif |
#if 0 |
||||||
#endif |
// Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5)
|
||||||
|
// for freq < 0.25, 275.2 mean, 716 worst
|
||||||
if (aa < 0) aa = (1 << 31) - 1; |
// high accuracy: 57.4 mean, 7559 worst
|
||||||
for (int i = 0; i < N; i++) { |
// freq < 0.25: 17.9 mean, 78 worst
|
||||||
gain += dgain; |
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
int32_t gain1, int32_t gain2, bool add) { |
||||||
v -= ((int64_t)aa * (int64_t)u) >> 29; |
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
u += v; |
int32_t gain = gain1; |
||||||
} |
int32_t phase = phase0; |
||||||
} |
#ifdef HIGH_ACCURACY |
||||||
#endif |
int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); |
||||||
|
int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5); |
||||||
#if 0 |
int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5); |
||||||
// Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5)
|
#else |
||||||
// high accuracy 2.9 mean, 143 worst
|
int32_t u = Sin::compute(phase); |
||||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
u = ((int64_t)u * gain) >> 24; |
||||||
int32_t gain1, int32_t gain2, bool add) { |
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
v = ((int64_t)v * gain) >> 24; |
||||||
int32_t gain = gain1; |
int32_t a = Sin::compute(freq >> 1) << 1; |
||||||
int32_t phase = phase0; |
#endif |
||||||
#ifdef HIGH_ACCURACY |
for (int i = 0; i < N; i++) { |
||||||
int32_t u = Sin::compute10(phase << 6); |
output[i] = u; |
||||||
int32_t lastu = Sin::compute10((phase - freq) << 6); |
v -= ((int64_t)a * (int64_t)u) >> 24; |
||||||
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; |
u += ((int64_t)a * (int64_t)v) >> 24; |
||||||
#else |
} |
||||||
int32_t u = Sin::compute(phase) << 6; |
} |
||||||
int32_t lastu = Sin::compute(phase - freq) << 6; |
#endif |
||||||
int32_t a = Sin::compute(freq + (1 << 22)) << 7; |
|
||||||
#endif |
#if 0 |
||||||
if (a < 0 && freq < 256) a = (1 << 31) - 1; |
// Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5)
|
||||||
if (a > 0 && freq > 0x7fff00) a = -(1 << 31); |
// with double accuracy initialization: mean 1.55, worst 58 (near freq = 0)
|
||||||
for (int i = 0; i < N; i++) { |
// with high accuracy: mean 4.2, worst 292 (near freq = 0.5)
|
||||||
gain += dgain; |
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
int32_t gain1, int32_t gain2, bool add) { |
||||||
//output[i] = u;
|
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; |
int32_t gain = gain1; |
||||||
lastu = u; |
int32_t phase = phase0; |
||||||
u = newu; |
#ifdef DOUBLE_ACCURACY |
||||||
} |
int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); |
||||||
} |
double a_d = sin(freq * (M_PI / (1 << 24))); |
||||||
#endif |
int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * |
||||||
|
(M_PI / (1 << 23))) + 0.5); |
||||||
void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq, |
int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); |
||||||
int32_t gain1, int32_t gain2, |
#else |
||||||
int32_t *fb_buf, int fb_shift, bool add) { |
#ifdef HIGH_ACCURACY |
||||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
int32_t u = Sin::compute10(phase << 6); |
||||||
int32_t gain = gain1; |
int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); |
||||||
int32_t phase = phase0; |
int32_t a = Sin::compute10(freq << 5); |
||||||
int32_t y0 = fb_buf[0]; |
v = ((int64_t)v * (int64_t)a) >> 29; |
||||||
int32_t y = fb_buf[1]; |
int32_t aa = ((int64_t)a * (int64_t)a) >> 29; |
||||||
if (add) { |
#else |
||||||
for (int i = 0; i < N; i++) { |
int32_t u = Sin::compute(phase) << 6; |
||||||
gain += dgain; |
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
||||||
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
int32_t a = Sin::compute(freq >> 1); |
||||||
y0 = y; |
v = ((int64_t)v * (int64_t)a) >> 17; |
||||||
y = Sin::lookup(phase + scaled_fb); |
int32_t aa = ((int64_t)a * (int64_t)a) >> 17; |
||||||
y = ((int64_t)y * (int64_t)gain) >> 24; |
#endif |
||||||
output[i] += y; |
#endif |
||||||
phase += freq; |
|
||||||
} |
if (aa < 0) aa = (1 << 31) - 1; |
||||||
} else { |
for (int i = 0; i < N; i++) { |
||||||
for (int i = 0; i < N; i++) { |
gain += dgain; |
||||||
gain += dgain; |
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
||||||
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
v -= ((int64_t)aa * (int64_t)u) >> 29; |
||||||
y0 = y; |
u += v; |
||||||
y = Sin::lookup(phase + scaled_fb); |
} |
||||||
y = ((int64_t)y * (int64_t)gain) >> 24; |
} |
||||||
output[i] = y; |
#endif |
||||||
phase += freq; |
|
||||||
} |
#if 0 |
||||||
} |
// Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5)
|
||||||
fb_buf[0] = y0; |
// high accuracy 2.9 mean, 143 worst
|
||||||
fb_buf[1] = y; |
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
} |
int32_t gain1, int32_t gain2, bool add) { |
||||||
|
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||||
|
int32_t gain = gain1; |
||||||
|
int32_t phase = phase0; |
||||||
|
#ifdef HIGH_ACCURACY |
||||||
|
int32_t u = Sin::compute10(phase << 6); |
||||||
|
int32_t lastu = Sin::compute10((phase - freq) << 6); |
||||||
|
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; |
||||||
|
#else |
||||||
|
int32_t u = Sin::compute(phase) << 6; |
||||||
|
int32_t lastu = Sin::compute(phase - freq) << 6; |
||||||
|
int32_t a = Sin::compute(freq + (1 << 22)) << 7; |
||||||
|
#endif |
||||||
|
if (a < 0 && freq < 256) a = (1 << 31) - 1; |
||||||
|
if (a > 0 && freq > 0x7fff00) a = -(1 << 31); |
||||||
|
for (int i = 0; i < N; i++) { |
||||||
|
gain += dgain; |
||||||
|
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
||||||
|
//output[i] = u;
|
||||||
|
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; |
||||||
|
lastu = u; |
||||||
|
u = newu; |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
@ -1,35 +1,42 @@ |
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Google Inc. |
* Copyright 2012 Google Inc. |
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
* you may not use this file except in compliance with the License. |
* you may not use this file except in compliance with the License. |
||||||
* You may obtain a copy of the License at |
* You may obtain a copy of the License at |
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software |
* Unless required by applicable law or agreed to in writing, software |
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
* See the License for the specific language governing permissions and |
* See the License for the specific language governing permissions and |
||||||
* limitations under the License. |
* limitations under the License. |
||||||
*/ |
*/ |
||||||
|
|
||||||
class FmOpKernel { |
#ifndef __FM_OP_KERNEL_H |
||||||
public: |
#define __FM_OP_KERNEL_H |
||||||
// gain1 and gain2 represent linear step: gain for sample i is
|
|
||||||
// gain1 + (1 + i) / 64 * (gain2 - gain1)
|
#include "controllers.h" |
||||||
|
|
||||||
// This is the basic FM operator. No feedback.
|
class FmOpKernel { |
||||||
static void compute(int32_t *output, const int32_t *input, |
public:
|
||||||
int32_t phase0, int32_t freq, |
// gain1 and gain2 represent linear step: gain for sample i is
|
||||||
int32_t gain1, int32_t gain2, bool add); |
// gain1 + (1 + i) / 64 * (gain2 - gain1)
|
||||||
|
|
||||||
// This is a sine generator, no feedback.
|
// This is the basic FM operator. No feedback.
|
||||||
static void compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
static void compute(int32_t *output, const int32_t *input, |
||||||
int32_t gain1, int32_t gain2, bool add); |
int32_t phase0, int32_t freq, |
||||||
|
int32_t gain1, int32_t gain2, bool add, const Controllers *controllers); |
||||||
// One op with feedback, no add.
|
|
||||||
static void compute_fb(int32_t *output, int32_t phase0, int32_t freq, |
// This is a sine generator, no feedback.
|
||||||
int32_t gain1, int32_t gain2, |
static void compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||||
int32_t *fb_buf, int fb_gain, bool add); |
int32_t gain1, int32_t gain2, bool add, const Controllers *controllers); |
||||||
}; |
|
||||||
|
// One op with feedback, no add.
|
||||||
|
static void compute_fb(int32_t *output, int32_t phase0, int32_t freq, |
||||||
|
int32_t gain1, int32_t gain2, |
||||||
|
int32_t *fb_buf, int fb_gain, bool add, const Controllers *controllers); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
||||||
|
Loading…
Reference in new issue