Nes: added pitch sweep for noise channel, freq.quantize mode (constrain frequencies to preset values when using note frequency)

Also added a handful of neat presets that mimick Nes sound effects
This commit is contained in:
Vesa
2014-05-29 22:48:13 +03:00
parent 19d105dc86
commit 50c5b0db03
8 changed files with 226 additions and 48 deletions

View File

@@ -83,6 +83,7 @@ NesObject::NesObject( NesInstrument * nes, const sample_rate_t samplerate, NoteP
m_ch1SweepCounter = 0;
m_ch2SweepCounter = 0;
m_ch4SweepCounter = 0;
m_12Last = 0.0f;
m_34Last = 0.0f;
@@ -91,24 +92,12 @@ NesObject::NesObject( NesInstrument * nes, const sample_rate_t samplerate, NoteP
m_nsf = NES_SIMPLE_FILTER * ( m_samplerate / 44100.0 );
// calculate initial frequency
const float freq = m_nph->frequency();
m_wlen1 = wavelength( freq * m_parent->m_freq1 );
m_wlen2 = wavelength( freq * m_parent->m_freq2 );
m_wlen3 = wavelength( freq * m_parent->m_freq3 );
if( m_parent->m_ch4NoiseFreqMode.value() )
{
m_wlen4 = wavelength( freq );
}
else
{
m_wlen4 = wavelength( NOISE_FREQS[ 15 - static_cast<int>( m_parent->m_ch4NoiseFreq.value() ) ] );
}
m_lastNoteFreq = freq;
m_lastNoteFreq = 0;
m_lastNoiseFreq = -1.0f; // value that is always different than noisefreq so it gets updated at start
m_vibratoPhase = 0;
updatePitch();
}
@@ -155,10 +144,19 @@ void NesObject::renderOutput( sampleFrame * buf, fpp_t frames )
int ch1SweepRate = wavelength( floorf( 120.0 / ( m_parent->m_ch1SweepRate.value() + 1 ) ) );
int ch2SweepRate = wavelength( floorf( 120.0 / ( m_parent->m_ch2SweepRate.value() + 1 ) ) );
int ch4SweepRate = wavelength( floorf( 60.0f / ( 8.0f - qAbs( m_parent->m_ch4Sweep.value() ) ) ) );
int ch1Sweep = static_cast<int>( m_parent->m_ch1SweepAmt.value() * -1.0 );
int ch2Sweep = static_cast<int>( m_parent->m_ch2SweepAmt.value() * -1.0 );
int ch4Sweep = 0;
if( m_parent->m_ch4Sweep.value() != 0.0f )
{
ch4Sweep = m_parent->m_ch4Sweep.value() > 0.0f
? -1
: 1;
}
// the amounts are inverted so we correct them here
if( ch1Sweep > 0 )
{
@@ -178,9 +176,6 @@ void NesObject::renderOutput( sampleFrame * buf, fpp_t frames )
ch2Sweep = -8 - ch2Sweep;
}
// is vibrato active
bool vibratoActive = m_parent->m_vibrato.value() > 0;
// start framebuffer loop
@@ -191,39 +186,15 @@ void NesObject::renderOutput( sampleFrame * buf, fpp_t frames )
// pitch update //
// //
////////////////////////////////
m_pitchUpdateCounter++;
if( m_pitchUpdateCounter >= m_pitchUpdateFreq )
{
updatePitch();
m_pitchUpdateCounter = 0;
float freq = m_nph->frequency();
// if vibrato is active, update vibrato
if( vibratoActive )
{
updateVibrato( &freq );
}
// check if frequency has changed, if so, update wavelengths of ch1-3
if( freq != m_lastNoteFreq )
{
m_wlen1 = wavelength( freq * m_parent->m_freq1 );
m_wlen2 = wavelength( freq * m_parent->m_freq2 );
m_wlen3 = wavelength( freq * m_parent->m_freq3 );
}
// noise channel can use either note freq or preset freqs
if( m_parent->m_ch4NoiseFreqMode.value() )
{
m_wlen4 = wavelength( freq );
}
else
{
m_wlen4 = wavelength( NOISE_FREQS[ 15 - static_cast<int>( m_parent->m_ch4NoiseFreq.value() ) ] );
}
m_lastNoteFreq = freq;
}
////////////////////////////////
// //
// channel 1 //
@@ -392,6 +363,26 @@ void NesObject::renderOutput( sampleFrame * buf, fpp_t frames )
}
}
m_ch4SweepCounter++;
if( m_ch4SweepCounter >= ch4SweepRate )
{
m_ch4SweepCounter = 0;
if( ch4Sweep != 0 )
{
int freqN = nearestNoiseFreq( static_cast<float>( m_samplerate ) / m_wlen4 );
freqN = qBound( 0, freqN + ch4Sweep, 15 );
m_wlen4 = wavelength( NOISE_FREQS[ freqN ] );
if( m_wlen4 == 0 && ch4Sweep == 1 ) // a workaround for sweep getting stuck on 0 wavelength
{
while( m_wlen4 == 0 )
{
m_wlen4 = wavelength( NOISE_FREQS[ ++freqN ] );
}
}
}
}
////////////////////////////////
// //
@@ -456,6 +447,41 @@ void NesObject::updateVibrato( float * freq )
}
void NesObject::updatePitch()
{
float freq = m_nph->frequency();
// if vibrato is active, update vibrato
if( m_parent->m_vibrato.value() > 0 )
{
updateVibrato( &freq );
}
// check if frequency has changed, if so, update wavelengths of ch1-3
if( freq != m_lastNoteFreq )
{
m_wlen1 = wavelength( freq * m_parent->m_freq1 );
m_wlen2 = wavelength( freq * m_parent->m_freq2 );
m_wlen3 = wavelength( freq * m_parent->m_freq3 );
}
// noise channel can use either note freq or preset freqs
if( m_parent->m_ch4NoiseFreqMode.value() && freq != m_lastNoteFreq )
{
float f = freq * 2.0f;
if( m_parent->m_ch4NoiseQuantize.value() ) // note freq can be quantized to the preset freqs
{
f = NOISE_FREQS[ nearestNoiseFreq( f ) ];
}
m_wlen4 = wavelength( f );
}
if( ! m_parent->m_ch4NoiseFreqMode.value() && m_lastNoiseFreq != m_parent->m_ch4NoiseFreq.value() )
{
m_wlen4 = wavelength( NOISE_FREQS[ 15 - static_cast<int>( m_parent->m_ch4NoiseFreq.value() ) ] );
m_lastNoiseFreq = m_parent->m_ch4NoiseFreq.value();
}
m_lastNoteFreq = freq;
}
NesInstrument::NesInstrument( InstrumentTrack * instrumentTrack ) :
@@ -505,6 +531,9 @@ NesInstrument::NesInstrument( InstrumentTrack * instrumentTrack ) :
m_ch4NoiseFreqMode( false, this ),
m_ch4NoiseFreq( 0.f, 0.f, 15.f, 1.f, this, tr( "Channel 4 Noise frequency" ) ),
m_ch4Sweep( 0.f, -7.f, 7.f, 1.f, this, tr( "Channel 4 Noise frequency sweep" ) ),
m_ch4NoiseQuantize( true, this ),
//master
m_masterVol( 1.0f, 0.0f, 2.0f, 0.01f, this, tr( "Master volume" ) ),
m_vibrato( 0.0f, 0.0f, 15.0f, 1.0f, this, tr( "Vibrato" ) )
@@ -794,13 +823,16 @@ NesInstrumentView::NesInstrumentView( Instrument * instrument, QWidget * parent
makeknob( m_ch4VolumeKnob, KNOB_X1, KNOB_Y4, "Volume", "", "" )
makeknob( m_ch4NoiseFreqKnob, KNOB_X2, KNOB_Y4, "Noise Frequency", "", "" )
makeknob( m_ch4EnvLenKnob, KNOB_X3, KNOB_Y4, "Envelope length", "", "" )
makeknob( m_ch4SweepKnob, KNOB_X4, KNOB_Y4, "Frequency sweep", "", "" )
makenesled( m_ch4EnabledBtn, KNOB_X1, KNOB_Y4 - 12, "Enable channel 4" )
makenesled( m_ch4EnvEnabledBtn, KNOB_X3, KNOB_Y4 - 12, "Enable envelope 4" )
makenesled( m_ch4EnvLoopedBtn, 129, KNOB_Y4 - 12, "Enable envelope 4 loop" )
makenesled( m_ch4NoiseModeBtn, 129, 203, "Noise mode" )
makenesled( m_ch4NoiseFreqModeBtn, 129, 224, "Use note frequency for noise" )
makenesled( m_ch4NoiseQuantizeBtn, 162, KNOB_Y4 - 12, "Quantize noise frequency when using note frequency" )
makenesled( m_ch4NoiseFreqModeBtn, 148, 203, "Use note frequency for noise" )
makenesled( m_ch4NoiseModeBtn, 148, 224, "Noise mode" )
//master
@@ -866,6 +898,9 @@ void NesInstrumentView::modelChanged()
m_ch4NoiseFreqModeBtn->setModel( &nes->m_ch4NoiseFreqMode );
m_ch4NoiseFreqKnob->setModel( &nes->m_ch4NoiseFreq );
m_ch4SweepKnob->setModel( &nes->m_ch4Sweep );
m_ch4NoiseQuantizeBtn->setModel( &nes->m_ch4NoiseQuantize );
//master
m_masterVolKnob->setModel( &nes->m_masterVol );
m_vibratoKnob->setModel( &nes->m_vibrato );

View File

@@ -86,6 +86,7 @@ public:
void renderOutput( sampleFrame * buf, fpp_t frames );
void updateVibrato( float * freq );
void updatePitch();
void updateLFSR( bool mode )
{
@@ -131,6 +132,19 @@ public:
: powf( f, e );
}
inline int nearestNoiseFreq( float f )
{
int n = 15;
for( int i = 15; i >= 0; i-- )
{
if( f >= NOISE_FREQS[ i ] )
{
n = i;
}
}
return n;
}
private:
NesInstrument * m_parent;
const sample_rate_t m_samplerate;
@@ -155,6 +169,7 @@ private:
int m_ch1SweepCounter;
int m_ch2SweepCounter;
int m_ch4SweepCounter;
uint16_t m_LFSR;
@@ -162,6 +177,7 @@ private:
float m_34Last;
float m_lastNoteFreq;
float m_lastNoiseFreq;
int m_maxWlen;
@@ -262,6 +278,9 @@ private:
BoolModel m_ch4NoiseFreqMode;
FloatModel m_ch4NoiseFreq;
FloatModel m_ch4Sweep;
BoolModel m_ch4NoiseQuantize;
//master
FloatModel m_masterVol;
FloatModel m_vibrato;
@@ -330,6 +349,9 @@ private:
pixmapButton * m_ch4NoiseFreqModeBtn;
knob * m_ch4NoiseFreqKnob;
knob * m_ch4SweepKnob;
pixmapButton * m_ch4NoiseQuantizeBtn;
//master
knob * m_masterVolKnob;
knob * m_vibratoKnob;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB