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