diff --git a/data/presets/Nescaline/Chomp.xpf b/data/presets/Nescaline/Chomp.xpf
new file mode 100644
index 000000000..38532ac83
--- /dev/null
+++ b/data/presets/Nescaline/Chomp.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Nescaline/Detune_lead.xpf b/data/presets/Nescaline/Detune_lead.xpf
new file mode 100644
index 000000000..d9fd507a6
--- /dev/null
+++ b/data/presets/Nescaline/Detune_lead.xpf
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Nescaline/Engine_overheats.xpf b/data/presets/Nescaline/Engine_overheats.xpf
new file mode 100644
index 000000000..0c3c0fdf2
--- /dev/null
+++ b/data/presets/Nescaline/Engine_overheats.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Nescaline/Fireball_flick.xpf b/data/presets/Nescaline/Fireball_flick.xpf
new file mode 100644
index 000000000..f50746e9b
--- /dev/null
+++ b/data/presets/Nescaline/Fireball_flick.xpf
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/presets/Nescaline/Mega_weapon.xpf b/data/presets/Nescaline/Mega_weapon.xpf
new file mode 100644
index 000000000..a0c47c03f
--- /dev/null
+++ b/data/presets/Nescaline/Mega_weapon.xpf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/nes/Nes.cpp b/plugins/nes/Nes.cpp
index 387308a19..0ba50020c 100644
--- a/plugins/nes/Nes.cpp
+++ b/plugins/nes/Nes.cpp
@@ -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( 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( m_parent->m_ch1SweepAmt.value() * -1.0 );
int ch2Sweep = static_cast( 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( 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( 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( 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 );
diff --git a/plugins/nes/Nes.h b/plugins/nes/Nes.h
index b8e0da20e..6a80f0974 100644
--- a/plugins/nes/Nes.h
+++ b/plugins/nes/Nes.h
@@ -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;
diff --git a/plugins/nes/artwork.png b/plugins/nes/artwork.png
index ac7dc4abb..e78ca6fbf 100644
Binary files a/plugins/nes/artwork.png and b/plugins/nes/artwork.png differ