diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 8f2c0b699..d1c741e95 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -481,6 +481,14 @@ sf2InstrumentView knob { qproperty-lineWidth: 2; } +sfxrInstrumentView knob { + color: #b06319; + qproperty-outerColor: rgb(194, 177, 145); + qproperty-innerRadius: 2; + qproperty-outerRadius: 10; + qproperty-lineWidth: 2; +} + opl2instrumentView knob { color: rgb(128,128,128); qproperty-outerColor: rgb(255,255,255); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 0cbdc4359..6f315b792 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -15,6 +15,7 @@ ADD_SUBDIRECTORY(papu) ADD_SUBDIRECTORY(patman) ADD_SUBDIRECTORY(peak_controller_effect) ADD_SUBDIRECTORY(sf2_player) +ADD_SUBDIRECTORY(sfxr) ADD_SUBDIRECTORY(sid) ADD_SUBDIRECTORY(spectrum_analyzer) ADD_SUBDIRECTORY(stereo_enhancer) diff --git a/plugins/sfxr/CMakeLists.txt b/plugins/sfxr/CMakeLists.txt new file mode 100644 index 000000000..2fe490d1e --- /dev/null +++ b/plugins/sfxr/CMakeLists.txt @@ -0,0 +1,3 @@ +INCLUDE(BuildPlugin) + +BUILD_PLUGIN(sfxr sfxr.cpp sfxr.h MOCFILES sfxr.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) diff --git a/plugins/sfxr/artwork.png b/plugins/sfxr/artwork.png new file mode 100644 index 000000000..15f313d45 Binary files /dev/null and b/plugins/sfxr/artwork.png differ diff --git a/plugins/sfxr/blip_active.png b/plugins/sfxr/blip_active.png new file mode 100644 index 000000000..f3113f772 Binary files /dev/null and b/plugins/sfxr/blip_active.png differ diff --git a/plugins/sfxr/blip_inactive.png b/plugins/sfxr/blip_inactive.png new file mode 100644 index 000000000..e8e5ca112 Binary files /dev/null and b/plugins/sfxr/blip_inactive.png differ diff --git a/plugins/sfxr/explosion_active.png b/plugins/sfxr/explosion_active.png new file mode 100644 index 000000000..b6af2a916 Binary files /dev/null and b/plugins/sfxr/explosion_active.png differ diff --git a/plugins/sfxr/explosion_inactive.png b/plugins/sfxr/explosion_inactive.png new file mode 100644 index 000000000..67c89f013 Binary files /dev/null and b/plugins/sfxr/explosion_inactive.png differ diff --git a/plugins/sfxr/hit_active.png b/plugins/sfxr/hit_active.png new file mode 100644 index 000000000..5bc6c9a14 Binary files /dev/null and b/plugins/sfxr/hit_active.png differ diff --git a/plugins/sfxr/hit_inactive.png b/plugins/sfxr/hit_inactive.png new file mode 100644 index 000000000..a16f7eca3 Binary files /dev/null and b/plugins/sfxr/hit_inactive.png differ diff --git a/plugins/sfxr/jump_active.png b/plugins/sfxr/jump_active.png new file mode 100644 index 000000000..6f1ff1ee5 Binary files /dev/null and b/plugins/sfxr/jump_active.png differ diff --git a/plugins/sfxr/jump_inactive.png b/plugins/sfxr/jump_inactive.png new file mode 100644 index 000000000..cc67812eb Binary files /dev/null and b/plugins/sfxr/jump_inactive.png differ diff --git a/plugins/sfxr/laser_active.png b/plugins/sfxr/laser_active.png new file mode 100644 index 000000000..04a5de94c Binary files /dev/null and b/plugins/sfxr/laser_active.png differ diff --git a/plugins/sfxr/laser_inactive.png b/plugins/sfxr/laser_inactive.png new file mode 100644 index 000000000..bf7eb18d1 Binary files /dev/null and b/plugins/sfxr/laser_inactive.png differ diff --git a/plugins/sfxr/logo.png b/plugins/sfxr/logo.png new file mode 100644 index 000000000..a39e4e865 Binary files /dev/null and b/plugins/sfxr/logo.png differ diff --git a/plugins/sfxr/mutate_active.png b/plugins/sfxr/mutate_active.png new file mode 100644 index 000000000..31cf797b1 Binary files /dev/null and b/plugins/sfxr/mutate_active.png differ diff --git a/plugins/sfxr/mutate_inactive.png b/plugins/sfxr/mutate_inactive.png new file mode 100644 index 000000000..31afa4c0e Binary files /dev/null and b/plugins/sfxr/mutate_inactive.png differ diff --git a/plugins/sfxr/pickup_active.png b/plugins/sfxr/pickup_active.png new file mode 100644 index 000000000..69c81b33c Binary files /dev/null and b/plugins/sfxr/pickup_active.png differ diff --git a/plugins/sfxr/pickup_inactive.png b/plugins/sfxr/pickup_inactive.png new file mode 100644 index 000000000..a4502ce56 Binary files /dev/null and b/plugins/sfxr/pickup_inactive.png differ diff --git a/plugins/sfxr/powerup_active.png b/plugins/sfxr/powerup_active.png new file mode 100644 index 000000000..6be7826cc Binary files /dev/null and b/plugins/sfxr/powerup_active.png differ diff --git a/plugins/sfxr/powerup_inactive.png b/plugins/sfxr/powerup_inactive.png new file mode 100644 index 000000000..c12fc18f9 Binary files /dev/null and b/plugins/sfxr/powerup_inactive.png differ diff --git a/plugins/sfxr/randomize_active.png b/plugins/sfxr/randomize_active.png new file mode 100644 index 000000000..e730c42fe Binary files /dev/null and b/plugins/sfxr/randomize_active.png differ diff --git a/plugins/sfxr/randomize_inactive.png b/plugins/sfxr/randomize_inactive.png new file mode 100644 index 000000000..147c75f70 Binary files /dev/null and b/plugins/sfxr/randomize_inactive.png differ diff --git a/plugins/sfxr/readme.txt b/plugins/sfxr/readme.txt new file mode 100644 index 000000000..27882c77f --- /dev/null +++ b/plugins/sfxr/readme.txt @@ -0,0 +1,170 @@ +This is a port of sfxr to LMMS, ported by Wong Cho Ching. + +NOTE: Do NOT remove the MIT license below to prevent legal problem. +Original Readme File: + +(http://www.drpetter.se/project_sfxr.html) + +----------------------------- +sfxr - sound effect generator +----------------------------- + by DrPetter, 2007-12-14 + developed for LD48#10 +----------------------------- + + +Basic usage: + +Start the application, then hit +some of the buttons on the left +side to generate random sounds +matching the button descriptions. + +Press "Export .WAV" to save the +current sound as a WAV audio file. +Click the buttons below to change +WAV format in terms of bits per +sample and sample rate. + +If you find a sound that is sort +of interesting but not quite what +you want, you can drag some sliders +around until it sounds better. + +The Randomize button generates +something completely random. + +Mutate slightly alters the current +parameters to automatically create +a variation of the sound. + + + +Advanced usage: + +Figure out what each slider does and +use them to adjust particular aspects +of the current sound... + +Press the right mouse button on a slider +to reset it to a value of zero. + +Press Space or Enter to play the current sound. + +The Save/Load sound buttons allow saving +and loading of program parameters to work +on a sound over several sessions. + +Volume setting is saved with the sound and +exported to WAV. If you increase it too much +there's a risk of clipping. + +Some parameters influence the sound during +playback (particularly when using a non-zero +repeat speed), and dragging these sliders +can cause some interesting effects. +To record this you will need to use an external +recording application, for instance Audacity. +Set the recording source in that application +to "Wave", "Stereo Mix", "Mixed Output" or similar. + +Using an external sound editor to capture and edit +sound can also be used to string several sounds +together for more complex results. + +Parameter description: +- The top four buttons select base waveform +- First four parameters control the volume envelope + Attack is the beginning of the sound, + longer attack means a smoother start. + Sustain is how long the volume is held constant + before fading out. + Increase Sustain Punch to cause a popping + effect with increased (and falling) volume + during the sustain phase. + Decay is the fade-out time. +- Next six are for controlling the sound pitch or + frequency. + Start frequency is pretty obvious. Has a large + impact on the overall sound. + Min frequency represents a cutoff that stops all + sound if it's passed during a downward slide. + Slide sets the speed at which the frequency should + be swept (up or down). + Delta slide is the "slide of slide", or rate of change + in the slide speed. + Vibrato depth/speed makes for an oscillating + frequency effect at various strengths and rates. +- Then we have two parameters for causing an abrupt + change in pitch after a ceratin delay. + Amount is pitch change (up or down) + and Speed indicates time to wait before changing + the pitch. +- Following those are two parameters specific to the + squarewave waveform. + The duty cycle of a square describes its shape + in terms of how large the positive vs negative + sections are. It can be swept up or down by + changing the second parameter. +- Repeat speed, when not zero, causes the frequency + and duty parameters to be reset at regular intervals + while the envelope and filter continue unhindered. + This can make for some interesting pulsating effects. +- Phaser offset overlays a delayed copy of the audio + stream on top of itself, resulting in a kind of tight + reverb or sci-fi effect. + This parameter can also be swept like many others. +- Finally, the bottom five sliders control two filters + which are applied after all other effects. + The first one is a resonant lowpass filter which has + a sweepable cutoff frequency. + The other is a highpass filter which can be used to + remove undesired low frequency hum in "light" sounds. + + +---------------------- + + +License +------- + +Basically, I don't care what you do with it, anything goes. + +To please all the troublesome folks who request a formal license, +I attach the "MIT license" as follows: + +-- + +Copyright (c) 2007 Tomas Pettersson + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + + +---------------------- + +http://www.drpetter.se + + drpetter@gmail.com + +---------------------- + diff --git a/plugins/sfxr/sfxr.cpp b/plugins/sfxr/sfxr.cpp new file mode 100644 index 000000000..01beac525 --- /dev/null +++ b/plugins/sfxr/sfxr.cpp @@ -0,0 +1,1052 @@ +/* + * sfxr.cpp - port of sfxr to LMMS + * Originally written by Tomas Pettersson. For the original license, + * please read readme.txt in this directory + * + * Copyright (c) 2014 Wong Cho Ching + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include + +#define rnd(n) (rand()%(n+1)) + +#define PI 3.14159265f + +float frnd(float range) +{ + return (float)rnd(10000)/10000*range; +} + + +#include + +#include "sfxr.h" +#include "engine.h" +#include "InstrumentTrack.h" +#include "knob.h" +#include "note_play_handle.h" +#include "pixmap_button.h" +#include "song_editor.h" +#include "templates.h" +#include "tooltip.h" +#include "song.h" + +#include "embed.cpp" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT sfxr_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "sfxr", + QT_TRANSLATE_NOOP( "pluginBrowser", + "LMMS port of sfxr" ), + "Wong Cho Ching", + 0x0100, + Plugin::Instrument, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + +} + + + + +SfxrSynth::SfxrSynth( const sfxrInstrument * s ): + s(s), + playing_sample( true ) +{ + resetSample( false ); +} + + + + +SfxrSynth::~SfxrSynth() +{ + +} + + + + +void SfxrSynth::resetSample( bool restart ) +{ + if(!restart) + { + phase=0; + } + fperiod=100.0/(s->m_startFreqModel.value()*s->m_startFreqModel.value()+0.001); + period=(int)fperiod; + fmaxperiod=100.0/(s->m_minFreqModel.value()*s->m_minFreqModel.value()+0.001); + fslide=1.0-pow((double)s->m_slideModel.value(), 3.0)*0.01; + fdslide=-pow((double)s->m_dSlideModel.value(), 3.0)*0.000001; + square_duty=0.5f-s->m_sqrDutyModel.value()*0.5f; + square_slide=-s->m_sqrSweepModel.value()*0.00005f; + if(s->m_changeAmtModel.value()>=0.0f) + arp_mod=1.0-pow((double)s->m_changeAmtModel.value(), 2.0)*0.9; + else + arp_mod=1.0+pow((double)s->m_changeAmtModel.value(), 2.0)*10.0; + arp_time=0; + arp_limit=(int)(pow(1.0f-s->m_changeSpeedModel.value(), 2.0f)*20000+32); + if(s->m_changeSpeedModel.value()==1.0f) + arp_limit=0; + if(!restart) + { + // reset filter + fltp=0.0f; + fltdp=0.0f; + fltw=pow(s->m_lpFilCutModel.value(), 3.0f)*0.1f; + fltw_d=1.0f+s->m_lpFilCutSweepModel.value()*0.0001f; + fltdmp=5.0f/(1.0f+pow(s->m_lpFilResoModel.value(), 2.0f)*20.0f)*(0.01f+fltw); + if(fltdmp>0.8f) fltdmp=0.8f; + fltphp=0.0f; + flthp=pow(s->m_hpFilCutModel.value(), 2.0f)*0.1f; + flthp_d=1.0+s->m_hpFilCutSweepModel.value()*0.0003f; + // reset vibrato + vib_phase=0.0f; + vib_speed=pow(s->m_vibSpeedModel.value(), 2.0f)*0.01f; + vib_amp=s->m_vibDepthModel.value()*0.5f; + // reset envelope + env_vol=0.0f; + env_stage=0; + env_time=0; + env_length[0]=(int)(s->m_attModel.value()*s->m_attModel.value()*100000.0f); + env_length[1]=(int)(s->m_holdModel.value()*s->m_holdModel.value()*100000.0f); + env_length[2]=(int)(s->m_decModel.value()*s->m_decModel.value()*100000.0f); + + fphase=pow(s->m_phaserOffsetModel.value(), 2.0f)*1020.0f; + if(s->m_phaserOffsetModel.value()<0.0f) fphase=-fphase; + fdphase=pow(s->m_phaserSweepModel.value(), 2.0f)*1.0f; + if(s->m_phaserSweepModel.value()<0.0f) fdphase=-fdphase; + iphase=abs((int)fphase); + ipp=0; + for(int i=0;i<1024;i++) + phaser_buffer[i]=0.0f; + + for(int i=0;i<32;i++) + noise_buffer[i]=frnd(2.0f)-1.0f; + + rep_time=0; + rep_limit=(int)(pow(1.0f-s->m_repeatSpeedModel.value(), 2.0f)*20000+32); + if(s->m_repeatSpeedModel.value()==0.0f) + rep_limit=0; + } +} + + + + +void SfxrSynth::update( sampleFrame * buffer, const fpp_t frameNum ) +{ + for(int i=0;i=rep_limit) + { + rep_limit=0; + resetSample(true); + } + + // frequency envelopes/arpeggios + arp_time++; + if(arp_limit!=0 && arp_time>=arp_limit) + { + arp_limit=0; + fperiod*=arp_mod; + } + fslide+=fdslide; + fperiod*=fslide; + if(fperiod>fmaxperiod) + { + fperiod=fmaxperiod; + if(s->m_minFreqModel.value()>0.0f) + playing_sample=false; + } + float rfperiod=fperiod; + if(vib_amp>0.0f) + { + vib_phase+=vib_speed; + rfperiod=fperiod*(1.0+sin(vib_phase)*vib_amp); + } + period=(int)rfperiod; + if(period<8) period=8; + square_duty+=square_slide; + if(square_duty<0.0f) square_duty=0.0f; + if(square_duty>0.5f) square_duty=0.5f; + // volume envelope + env_time++; + if(env_time>env_length[env_stage]) + { + env_time=0; + env_stage++; + if(env_stage==3) + playing_sample=false; + } + if(env_stage==0) + env_vol=(float)env_time/env_length[0]; + if(env_stage==1) + env_vol=1.0f+pow(1.0f-(float)env_time/env_length[1], 1.0f)*2.0f*s->m_susModel.value(); + if(env_stage==2) + env_vol=1.0f-(float)env_time/env_length[2]; + + // phaser step + fphase+=fdphase; + iphase=abs((int)fphase); + if(iphase>1023) iphase=1023; + + if(flthp_d!=0.0f) + { + flthp*=flthp_d; + if(flthp<0.00001f) flthp=0.00001f; + if(flthp>0.1f) flthp=0.1f; + } + + float ssample=0.0f; + for(int si=0;si<8;si++) // 8x supersampling + { + float sample=0.0f; + phase++; + if(phase>=period) + { +// phase=0; + phase%=period; + if(s->m_waveFormModel.value()==3) + for(int i=0;i<32;i++) + noise_buffer[i]=frnd(2.0f)-1.0f; + } + // base waveform + float fp=(float)phase/period; + switch(s->m_waveFormModel.value()) + { + case 0: // square + if(fp0.1f) fltw=0.1f; + if(s->m_lpFilCutModel.value()!=1.0f) + { + fltdp+=(sample-fltp)*fltw; + fltdp-=fltdp*fltdmp; + } + else + { + fltp=sample; + fltdp=0.0f; + } + fltp+=fltdp; + // hp filter + fltphp+=fltp-pp; + fltphp-=fltphp*flthp; + sample=fltphp; + // phaser + phaser_buffer[ipp&1023]=sample; + sample+=phaser_buffer[(ipp-iphase+1024)&1023]; + ipp=(ipp+1)&1023; + // final accumulation and envelope application + ssample+=sample*env_vol; + } + //ssample=ssample/8*master_vol; + + //ssample*=2.0f*sound_vol; + ssample*=0.05f; + + if(buffer!=NULL) + { + if(ssample>1.0f) ssample=1.0f; + if(ssample<-1.0f) ssample=-1.0f; + for( ch_cnt_t j=0; j < DEFAULT_CHANNELS; j++ ) + { + buffer[i][j]=ssample; + } + } + } +} + + + + +bool SfxrSynth::isPlaying() const +{ + return playing_sample; +} + + +sfxrInstrument::sfxrInstrument( InstrumentTrack * _instrument_track ) : + Instrument( _instrument_track, &sfxr_plugin_descriptor ), + m_attModel(0.0f, this), + m_holdModel(0.3f, this), + m_susModel(0.0f, this), + m_decModel(0.4f, this), + + m_startFreqModel(0.3f, this), + m_minFreqModel(0.0f, this), + m_slideModel(0.0f, this), + m_dSlideModel(0.0f, this), + m_vibDepthModel(0.0f, this), + m_vibSpeedModel(0.0f, this), + + m_changeAmtModel(0.0f, this), + m_changeSpeedModel(0.0f, this), + + m_sqrDutyModel(0.0f, this), + m_sqrSweepModel(0.0f, this), + + m_repeatSpeedModel(0.0f, this), + + m_phaserOffsetModel(0.0f, this), + m_phaserSweepModel(0.0f, this), + + m_lpFilCutModel(1.0f, this), + m_lpFilCutSweepModel(0.0f, this), + m_lpFilResoModel(0.0f, this), + m_hpFilCutModel(0.0f, this), + m_hpFilCutSweepModel(0.0f, this), + m_waveFormModel( SQR_WAVE, 0, WAVES_NUM-1, this, tr( "Wave Form" ) ) +{ +} + + + + +sfxrInstrument::~sfxrInstrument() +{ +} + + + + +void sfxrInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + _this.setAttribute( "version", "1" ); + m_attModel.saveSettings( _doc, _this, "att" ); + m_holdModel.saveSettings( _doc, _this, "hold" ); + m_susModel.saveSettings( _doc, _this, "sus" ); + m_decModel.saveSettings( _doc, _this, "dec" ); + + m_startFreqModel.saveSettings( _doc, _this, "startFreq" ); + m_minFreqModel.saveSettings( _doc, _this, "minFreq" ); + m_slideModel.saveSettings( _doc, _this, "slide" ); + m_dSlideModel.saveSettings( _doc, _this, "dSlide" ); + m_vibDepthModel.saveSettings( _doc, _this, "vibDepth" ); + m_vibSpeedModel.saveSettings( _doc, _this, "vibSpeed" ); + + m_changeAmtModel.saveSettings( _doc, _this, "changeAmt" ); + m_changeSpeedModel.saveSettings( _doc, _this, "changeSpeed" ); + + m_sqrDutyModel.saveSettings( _doc, _this, "sqrDuty" ); + m_sqrSweepModel.saveSettings( _doc, _this, "sqrSweep" ); + + m_repeatSpeedModel.saveSettings( _doc, _this, "repeatSpeed" ); + + m_phaserOffsetModel.saveSettings( _doc, _this, "phaserOffset" ); + m_phaserSweepModel.saveSettings( _doc, _this, "phaserSweep" ); + + m_lpFilCutModel.saveSettings( _doc, _this, "lpFilCut" ); + m_lpFilCutSweepModel.saveSettings( _doc, _this, "lpFilCutSweep" ); + m_lpFilResoModel.saveSettings( _doc, _this, "lpFilReso" ); + m_hpFilCutModel.saveSettings( _doc, _this, "hpFilCut" ); + m_hpFilCutSweepModel.saveSettings( _doc, _this, "hpFilCutSweep" ); + + m_waveFormModel.saveSettings( _doc, _this, "waveForm" ); +} + + + + +void sfxrInstrument::loadSettings( const QDomElement & _this ) +{ + + m_attModel.loadSettings(_this, "att" ); + m_holdModel.loadSettings( _this, "hold" ); + m_susModel.loadSettings( _this, "sus" ); + m_decModel.loadSettings( _this, "dec" ); + + m_startFreqModel.loadSettings( _this, "startFreq" ); + m_minFreqModel.loadSettings( _this, "minFreq" ); + m_slideModel.loadSettings( _this, "slide" ); + m_dSlideModel.loadSettings( _this, "dSlide" ); + m_vibDepthModel.loadSettings( _this, "vibDepth" ); + m_vibSpeedModel.loadSettings( _this, "vibSpeed" ); + + m_changeAmtModel.loadSettings( _this, "changeAmt" ); + m_changeSpeedModel.loadSettings( _this, "changeSpeed" ); + + m_sqrDutyModel.loadSettings( _this, "sqrDuty" ); + m_sqrSweepModel.loadSettings( _this, "sqrSweep" ); + + m_repeatSpeedModel.loadSettings( _this, "repeatSpeed" ); + + m_phaserOffsetModel.loadSettings( _this, "phaserOffset" ); + m_phaserSweepModel.loadSettings( _this, "phaserSweep" ); + + m_lpFilCutModel.loadSettings( _this, "lpFilCut" ); + m_lpFilCutSweepModel.loadSettings( _this, "lpFilCutSweep" ); + m_lpFilResoModel.loadSettings( _this, "lpFilReso" ); + m_hpFilCutModel.loadSettings( _this, "hpFilCut" ); + m_hpFilCutSweepModel.loadSettings( _this, "hpFilCutSweep" ); + + m_waveFormModel.loadSettings( _this, "waveForm" ); + +} + + + + +QString sfxrInstrument::nodeName() const +{ + return( sfxr_plugin_descriptor.name ); +} + + + + +void sfxrInstrument::playNote(notePlayHandle * _n, sampleFrame * _working_buffer ) +{ + m_synthMutex.lock(); + fpp_t frameNum = _n->framesLeftForCurrentPeriod(); + if ( _n->totalFramesPlayed() == 0 ) + { + _n->m_pluginData = new SfxrSynth( this ); + } + else if( static_cast(_n->m_pluginData)->isPlaying() == false ) + { + _n->noteOff(); + } + + static_cast(_n->m_pluginData)->update( _working_buffer, frameNum ); + m_synthMutex.unlock(); + + instrumentTrack()->processAudioBuffer( _working_buffer, frameNum, NULL ); +} + + + + +void sfxrInstrument::deleteNotePluginData( notePlayHandle * _n ) +{ + delete static_cast( _n->m_pluginData ); +} + + + + +PluginView * sfxrInstrument::instantiateView( QWidget * _parent ) +{ + return( new sfxrInstrumentView( this, _parent ) ); +} + + + + +void sfxrInstrument::resetModels() +{ + + m_attModel.reset(); + m_holdModel.reset(); + m_susModel.reset(); + m_decModel.reset(); + + m_startFreqModel.reset(); + m_minFreqModel.reset(); + m_slideModel.reset(); + m_dSlideModel.reset(); + m_vibDepthModel.reset(); + m_vibSpeedModel.reset(); + + m_changeAmtModel.reset(); + m_changeSpeedModel.reset(); + + m_sqrDutyModel.reset(); + m_sqrSweepModel.reset(); + + m_repeatSpeedModel.reset(); + + m_phaserOffsetModel.reset(); + m_phaserSweepModel.reset(); + + m_lpFilCutModel.reset(); + m_lpFilCutSweepModel.reset(); + m_lpFilResoModel.reset(); + m_hpFilCutModel.reset(); + m_hpFilCutSweepModel.reset(); + + m_waveFormModel.reset(); +} + + + + +class sfxrKnob : public knob +{ +public: + sfxrKnob( QWidget * _parent ) : + knob( knobStyled, _parent ) + { + setFixedSize( 20, 20 ); + setCenterPointX( 10.0 ); + setCenterPointY( 10.0 ); + setTotalAngle( 270.0 ); + setLineWidth( 1 ); + } +}; + + + + +#define createKnob(_knob, _x, _y, _name)\ + _knob = new sfxrKnob( this ); \ + _knob->setHintText( tr( _name ":" ), "" ); \ + _knob->move( _x, _y ); \ + toolTip::add( _knob, tr( _name ) ); + + + + +#define createButton(_button, _x, _y, _name, _resName)\ + _button = new pixmapButton( this, tr( "Sine wave" ) );\ + _button->move( _x, _y );\ + _button->setActiveGraphic( embed::getIconPixmap( _resName "_active" ) );\ + _button->setInactiveGraphic( embed::getIconPixmap( _resName "_inactive" ) );\ + toolTip::add( _button, tr( _name ) ); + + + + +#define createButtonLocalGraphic(_button, _x, _y, _name, _resName)\ + _button = new pixmapButton( this, tr( "Sine wave" ) );\ + _button->move( _x, _y );\ + _button->setActiveGraphic( PLUGIN_NAME::getIconPixmap( _resName "_active" ) );\ + _button->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( _resName "_inactive" ) );\ + toolTip::add( _button, tr( _name ) ); + + + + +sfxrInstrumentView::sfxrInstrumentView( Instrument * _instrument, + QWidget * _parent ) : + InstrumentView( _instrument, _parent ) +{ + srand(time(NULL)); + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + + createKnob(m_attKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*0, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*0, "Attack Time"); + createKnob(m_holdKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*1, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*0, "Sustain Time"); + createKnob(m_susKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*2, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*0, "Sustain Punch"); + createKnob(m_decKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*3, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*0, "Decay Time"); + + createKnob(m_startFreqKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*0, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Start Frequency"); + createKnob(m_minFreqKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*1, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Min Frequency"); + createKnob(m_slideKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*2, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Slide"); + createKnob(m_dSlideKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*3, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Delta Slide"); + createKnob(m_vibDepthKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*4, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Vibrato Depth"); + createKnob(m_vibSpeedKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*5, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*1, "Vibrato Speed"); + + createKnob(m_changeAmtKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*0, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*2, "Change Amount"); + createKnob(m_changeSpeedKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*1, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*2, "Change Speed"); + + createKnob(m_sqrDutyKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*3, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*2, "Squre Duty(Square wave only)"); + createKnob(m_sqrSweepKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*4, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*2, "Squre Sweep(Square wave only)"); + + createKnob(m_repeatSpeedKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*0, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*3, "Repeat Speed"); + + createKnob(m_phaserOffsetKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*2, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*3, "Phaser Offset"); + createKnob(m_phaserSweepKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*3, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*3, "Phaser Sweep"); + + createKnob(m_lpFilCutKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*0, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*4, "LP Filter Cutoff"); + createKnob(m_lpFilCutSweepKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*1, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*4, "LP Filter Cutoff Sweep"); + createKnob(m_lpFilResoKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*2, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*4, "LP Filter Resonance"); + createKnob(m_hpFilCutKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*3, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*4, "HP Filter Cutoff"); + createKnob(m_hpFilCutSweepKnob, KNOBS_BASE_X+KNOB_BLOCK_SIZE_X*4, KNOBS_BASE_Y+KNOB_BLOCK_SIZE_Y*4, "HP Filter Cutoff Sweep"); + + createButton(m_sqrWaveBtn, KNOBS_BASE_X+WAVEFORM_BUTTON_WIDTH*0, WAVEFORM_BASE_Y, "Square Wave", "square_wave"); + createButton(m_sawWaveBtn, KNOBS_BASE_X+WAVEFORM_BUTTON_WIDTH*1, WAVEFORM_BASE_Y, "Saw Wave", "saw_wave"); + createButton(m_sinWaveBtn, KNOBS_BASE_X+WAVEFORM_BUTTON_WIDTH*2, WAVEFORM_BASE_Y, "Sine Wave", "sin_wave"); + createButton(m_noiseWaveBtn, KNOBS_BASE_X+WAVEFORM_BUTTON_WIDTH*3, WAVEFORM_BASE_Y, "Noise", "white_noise_wave"); + + m_waveBtnGroup = new automatableButtonGroup( this ); + m_waveBtnGroup->addButton(m_sqrWaveBtn); + m_waveBtnGroup->addButton(m_sawWaveBtn); + m_waveBtnGroup->addButton(m_sinWaveBtn); + m_waveBtnGroup->addButton(m_noiseWaveBtn); + + + createButtonLocalGraphic(m_pickupBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*0, GENERATOR_BASE_Y, "Generate pick up/coin sfx", "pickup"); + createButtonLocalGraphic(m_laserBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*1, GENERATOR_BASE_Y, "Generate laser/shoot sfx", "laser"); + createButtonLocalGraphic(m_explosionBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*2, GENERATOR_BASE_Y, "Generate explosion sfx", "explosion"); + createButtonLocalGraphic(m_powerupBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*3, GENERATOR_BASE_Y, "Generate power up sfx", "powerup"); + createButtonLocalGraphic(m_hitBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*4, GENERATOR_BASE_Y, "Generate hit/hurt sfx", "hit"); + createButtonLocalGraphic(m_jumpBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*5, GENERATOR_BASE_Y, "Generate jump sfx", "jump"); + createButtonLocalGraphic(m_blipBtn, GENERATOR_BASE_X+GENERATOR_BUTTON_WIDTH*6, GENERATOR_BASE_Y, "Generate blip/select sfx", "blip"); + connect( m_pickupBtn, SIGNAL ( clicked() ), this, SLOT ( genPickup() ) ); + connect( m_laserBtn, SIGNAL ( clicked() ), this, SLOT ( genLaser() ) ); + connect( m_explosionBtn, SIGNAL ( clicked() ), this, SLOT ( genExplosion() ) ); + connect( m_powerupBtn, SIGNAL ( clicked() ), this, SLOT ( genPowerup() ) ); + connect( m_hitBtn, SIGNAL ( clicked() ), this, SLOT ( genHit() ) ); + connect( m_jumpBtn, SIGNAL ( clicked() ), this, SLOT ( genJump() ) ); + connect( m_blipBtn, SIGNAL ( clicked() ), this, SLOT ( genBlip() ) ); + + + createButtonLocalGraphic(m_randomizeBtn, RAND_BUTTON_X, RAND_BUTTON_Y, "Generate random sfx", "randomize"); + createButtonLocalGraphic(m_mutateBtn, MUTA_BUTTON_X, MUTA_BUTTON_Y, "Mutate sfx", "mutate"); + connect( m_randomizeBtn, SIGNAL ( clicked() ), this, SLOT ( randomize() ) ); + connect( m_mutateBtn, SIGNAL ( clicked() ), this, SLOT ( mutate() ) ); + + +} + + + + +void sfxrInstrumentView::modelChanged() +{ + sfxrInstrument * s = castModel(); + + m_attKnob->setModel( &s->m_attModel ); + m_holdKnob->setModel( &s->m_holdModel ); + m_susKnob->setModel( &s->m_susModel ); + m_decKnob->setModel( &s->m_decModel ); + + m_startFreqKnob->setModel( &s->m_startFreqModel ); + m_minFreqKnob->setModel( &s->m_minFreqModel ); + m_slideKnob->setModel( &s->m_slideModel ); + m_dSlideKnob->setModel( &s->m_dSlideModel ); + m_vibDepthKnob->setModel( &s->m_vibDepthModel ); + m_vibSpeedKnob->setModel( &s->m_vibSpeedModel ); + + m_changeAmtKnob->setModel( &s->m_changeAmtModel ); + m_changeSpeedKnob->setModel( &s->m_changeSpeedModel ); + + m_sqrDutyKnob->setModel( &s->m_sqrDutyModel ); + m_sqrSweepKnob->setModel( &s->m_sqrSweepModel ); + + m_repeatSpeedKnob->setModel( &s->m_repeatSpeedModel ); + + m_phaserOffsetKnob->setModel( &s->m_phaserOffsetModel ); + m_phaserSweepKnob->setModel( &s->m_phaserSweepModel ); + + m_lpFilCutKnob->setModel( &s->m_lpFilCutModel ); + m_lpFilCutSweepKnob->setModel( &s->m_lpFilCutSweepModel ); + m_lpFilResoKnob->setModel( &s->m_lpFilResoModel ); + m_hpFilCutKnob->setModel( &s->m_hpFilCutModel ); + m_hpFilCutSweepKnob->setModel( &s->m_hpFilCutSweepModel ); + + m_waveBtnGroup->setModel( &s->m_waveFormModel ); +} + + + + +void sfxrInstrumentView::genPickup() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + s->m_startFreqModel.setValue( 0.4f+frnd(0.5f) ); + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( frnd(0.1f) ); + s->m_decModel.setValue( 0.1f+frnd(0.4f) ); + s->m_susModel.setValue( 0.3f+frnd(0.3f) ); + + if(rnd(1)) + { + s->m_changeSpeedModel.setValue( 0.5f+frnd(0.2f) ); + s->m_changeAmtModel.setValue( 0.2f+frnd(0.4f) ); + } +} + + + + +void sfxrInstrumentView::genLaser() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + s->m_waveFormModel.setValue( rnd(2) ); + if(s->m_waveFormModel.value()==2 && rnd(1)) + s->m_waveFormModel.setValue( rnd(1) ); + + s->m_startFreqModel.setValue( 0.5f+frnd(0.5f) ); + s->m_minFreqModel.setValue( s->m_startFreqModel.value()-0.2f-frnd(0.6f) ); + + if(s->m_minFreqModel.value()<0.2f) + { + s->m_minFreqModel.setValue(0.2f); + } + + s->m_slideModel.setValue( -0.15f-frnd(0.2f) ); + + if(rnd(2)==0) + { + s->m_startFreqModel.setValue( 0.3f+frnd(0.6f) ); + s->m_minFreqModel.setValue( frnd(0.1f) ); + s->m_slideModel.setValue( -0.35f-frnd(0.3f) ); + } + + if(rnd(1)) + { + s->m_sqrDutyModel.setValue( frnd(0.5f) ); + s->m_sqrSweepModel.setValue( 0.2f ); + } + else + { + s->m_sqrDutyModel.setValue( 0.4f+frnd(0.5f) ); + s->m_sqrSweepModel.setValue( -frnd(0.7f) ); + } + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( 0.1f+frnd(0.2f) ); + s->m_decModel.setValue( frnd(0.4f) ); + + if(rnd(1)) + { + s->m_susModel.setValue( frnd(0.3f) ); + } + + if(rnd(2)==0) + { + s->m_phaserOffsetModel.setValue( frnd(0.2f) ); + s->m_phaserSweepModel.setValue( -frnd(0.2f) ); + } + + if(rnd(1)) + s->m_hpFilCutModel.setValue( frnd(0.3f) ); +} + + + + +void sfxrInstrumentView::genExplosion() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + s->m_waveFormModel.setValue( 3 ); + + if(rnd(1)) + { + s->m_startFreqModel.setValue( 0.1f+frnd(0.4f) ); + s->m_slideModel.setValue( -0.1f+frnd(0.4f) ); + } + else + { + s->m_startFreqModel.setValue( 0.2f+frnd(0.7f) ); + s->m_slideModel.setValue( -0.2f-frnd(0.2f) ); + } + s->m_startFreqModel.setValue( s->m_startFreqModel.value()*s->m_startFreqModel.value() ); + + if(rnd(4)==0) + { + s->m_slideModel.setValue( 0.0f ); + } + + if(rnd(2)==0) + { + s->m_repeatSpeedModel.setValue( 0.3f+frnd(0.5f) ); + } + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( 0.1f+frnd(0.3f) ); + s->m_decModel.setValue( 0.5f ); + if(rnd(1)==0) + { + s->m_phaserOffsetModel.setValue( -0.3f+frnd(0.9f) ); + s->m_phaserSweepModel.setValue( -frnd(0.3f) ); + } + s->m_susModel.setValue( 0.2f+frnd(0.6f) ); + + if(rnd(1)) + { + s->m_vibDepthModel.setValue( frnd(0.7f) ); + s->m_vibSpeedModel.setValue( frnd(0.6f) ); + } + if(rnd(2)==0) + { + s->m_changeSpeedModel.setValue( 0.6f+frnd(0.3f) ); + s->m_changeAmtModel.setValue( 0.8f-frnd(1.6f) ); + } + +} + + + + +void sfxrInstrumentView::genPowerup() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + if(rnd(1)) + s->m_waveFormModel.setValue( 1 ); + else + s->m_sqrDutyModel.setValue( frnd(0.6f) ); + if(rnd(1)) + { + s->m_startFreqModel.setValue( 0.2f+frnd(0.3f) ); + s->m_slideModel.setValue( 0.1f+frnd(0.4f) ); + s->m_repeatSpeedModel.setValue( 0.4f+frnd(0.4f) ); + } + else + { + s->m_startFreqModel.setValue( 0.2f+frnd(0.3f) ); + s->m_slideModel.setValue( 0.05f+frnd(0.2f) ); + if(rnd(1)) + { + s->m_vibDepthModel.setValue( frnd(0.7f) ); + s->m_vibSpeedModel.setValue( frnd(0.6f) ); + } + } + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( frnd(0.4f) ); + s->m_decModel.setValue( 0.1f+frnd(0.4f) ); +} + + + + +void sfxrInstrumentView::genHit() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + s->m_waveFormModel.setValue( rnd(2) ); + if(s->m_waveFormModel.value()==2) + { + s->m_waveFormModel.setValue( 3 ); + } + if(s->m_waveFormModel.value()==0) + { + s->m_sqrDutyModel.setValue( frnd(0.6f) ); + } + + s->m_startFreqModel.setValue( 0.2f+frnd(0.6f) ); + s->m_slideModel.setValue( -0.3f-frnd(0.4f) ); + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( frnd(0.1f) ); + s->m_decModel.setValue( 0.1f+frnd(0.2f) ); + if(rnd(1)) + { + s->m_hpFilCutModel.setValue( frnd(0.3f) ); + } +} + + + + +void sfxrInstrumentView::genJump() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + s->m_waveFormModel.setValue( 0 ); + s->m_sqrDutyModel.setValue( frnd(0.6f) ); + + s->m_startFreqModel.setValue( 0.3f+frnd(0.3f) ); + s->m_slideModel.setValue( 0.1f+frnd(0.2f) ); + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( 0.1f+frnd(0.3f) ); + s->m_decModel.setValue( 0.1f+frnd(0.2f) ); + + if(rnd(1)) + { + s->m_hpFilCutModel.setValue( frnd(0.3f) ); + } + if(rnd(1)) + { + + s->m_lpFilCutModel.setValue( 1.0f-frnd(0.6f) ); + } + +} + + + + +void sfxrInstrumentView::genBlip() +{ + sfxrInstrument * s = castModel(); + s->resetModels(); + + s->m_waveFormModel.setValue( rnd(1) ); + if( s->m_waveFormModel.value()==0 ) + { + s->m_sqrDutyModel.setValue( frnd(0.6f) ); + } + + s->m_startFreqModel.setValue( 0.2f+frnd(0.4f) ); + + s->m_attModel.setValue( 0.0f ); + s->m_holdModel.setValue( 0.1f+frnd(0.1f) ); + s->m_decModel.setValue( frnd(0.2f) ); + s->m_hpFilCutModel.setValue( 0.1f ); +} + + + + +void sfxrInstrumentView::randomize() +{ + sfxrInstrument * s = castModel(); + + s->m_startFreqModel.setValue( pow(frnd(2.0f)-1.0f, 2.0f) ); + if(rnd(1)) + { + s->m_startFreqModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f)+0.5f ); + } + s->m_minFreqModel.setValue( 0.0f ); + s->m_slideModel.setValue( pow(frnd(2.0f)-1.0f, 5.0f) ); + if( s->m_startFreqModel.value()>0.7f && s->m_slideModel.value()>0.2f ) + { + s->m_slideModel.setValue( -s->m_slideModel.value() ); + } + if( s->m_startFreqModel.value()<0.2f && s->m_slideModel.value()<-0.05f ) + { + s->m_slideModel.setValue( -s->m_slideModel.value() ); + } + s->m_dSlideModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + + s->m_sqrDutyModel.setValue( frnd(2.0f)-1.0f ); + s->m_sqrSweepModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + + s->m_vibDepthModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + s->m_vibSpeedModel.setValue( frnd(2.0f)-1.0f ); + //s->m_vibDelayModel.setValue( frnd(2.0f)-1.0f ); + + s->m_attModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + s->m_holdModel.setValue( pow(frnd(2.0f)-1.0f, 2.0f) ); + s->m_decModel.setValue( frnd(2.0f)-1.0f ); + s->m_susModel.setValue( pow(frnd(0.8f), 2.0f) ); + if(s->m_attModel.value()+s->m_holdModel.value()+s->m_decModel.value()<0.2f) + { + s->m_holdModel.setValue( s->m_holdModel.value()+0.2f+frnd(0.3f) ); + s->m_decModel.setValue( s->m_decModel.value()+0.2f+frnd(0.3f) ); + } + + s->m_lpFilResoModel.setValue( frnd(2.0f)-1.0f ); + s->m_lpFilCutModel.setValue( 1.0f-pow(frnd(1.0f), 3.0f) ); + s->m_lpFilCutSweepModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + if(s->m_lpFilCutModel.value()<0.1f && s->m_lpFilCutSweepModel.value()<-0.05f) + { + s->m_lpFilCutSweepModel.setValue( -s->m_lpFilCutSweepModel.value() ); + } + s->m_hpFilCutModel.setValue( pow(frnd(1.0f), 5.0f) ); + s->m_hpFilCutSweepModel.setValue( pow(frnd(2.0f)-1.0f, 5.0f) ); + + s->m_phaserOffsetModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + s->m_phaserSweepModel.setValue( pow(frnd(2.0f)-1.0f, 3.0f) ); + + s->m_repeatSpeedModel.setValue( frnd(2.0f)-1.0f ); + + s->m_changeSpeedModel.setValue( frnd(2.0f)-1.0f ); + s->m_changeAmtModel.setValue( frnd(2.0f)-1.0f ); + +} + + + + +void sfxrInstrumentView::mutate() +{ + sfxrInstrument * s = castModel(); + + if(rnd(1)) s->m_startFreqModel.setValue( s->m_startFreqModel.value()+frnd(0.1f)-0.05f ); + // if(rnd(1)) s->m_minFreqModel.setValue( s->m_minFreqModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_slideModel.setValue( s->m_slideModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_dSlideModel.setValue( s->m_dSlideModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_sqrDutyModel.setValue( s->m_sqrDutyModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_sqrSweepModel.setValue( s->m_sqrSweepModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_vibDepthModel.setValue( s->m_vibDepthModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_vibSpeedModel.setValue( s->m_vibSpeedModel.value()+frnd(0.1f)-0.05f ); + // if(rnd(1)) s->m_vibDelayModel.setValue( s->m_vibDelayModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_attModel.setValue( s->m_attModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_holdModel.setValue( s->m_holdModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_decModel.setValue( s->m_decModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_susModel.setValue( s->m_susModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_lpFilResoModel.setValue( s->m_lpFilResoModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_lpFilCutModel.setValue( s->m_lpFilCutModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_lpFilCutSweepModel.setValue( s->m_lpFilCutSweepModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_hpFilCutModel.setValue( s->m_hpFilCutModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_hpFilCutSweepModel.setValue( s->m_hpFilCutSweepModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_phaserOffsetModel.setValue( s->m_phaserOffsetModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_phaserSweepModel.setValue( s->m_phaserSweepModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_repeatSpeedModel.setValue( s->m_repeatSpeedModel.value()+frnd(0.1f)-0.05f ); + + if(rnd(1)) s->m_changeSpeedModel.setValue( s->m_changeSpeedModel.value()+frnd(0.1f)-0.05f ); + if(rnd(1)) s->m_changeAmtModel.setValue( s->m_changeAmtModel.value()+frnd(0.1f)-0.05f ); + +} + + + + +extern "C" +{ + +// necessary for getting instance out of shared lib +Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data ) +{ + return( new sfxrInstrument( static_cast( _data ) ) ); +} + + +} + + + +#include "moc_sfxr.cxx" diff --git a/plugins/sfxr/sfxr.h b/plugins/sfxr/sfxr.h new file mode 100644 index 000000000..2d9934219 --- /dev/null +++ b/plugins/sfxr/sfxr.h @@ -0,0 +1,301 @@ +/* + * sfxr.h - declaration of classes of the LMMS sfxr plugin + * Originally written by Tomas Pettersson. For the original license, + * please read readme.txt in this directory + * + * Copyright (c) 2014 Wong Cho Ching + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _SFXR_H +#define _SFXR_H + +#include "Instrument.h" +#include "InstrumentView.h" +#include "knob.h" +#include "graph.h" +#include "pixmap_button.h" +#include "led_checkbox.h" + + +enum SfxrWaves +{ + SQR_WAVE, SAW_WAVE, SINE_WAVE, NOISE_WAVE, WAVES_NUM +}; + +const int WAVEFORM_BASE_X = 20; +const int WAVEFORM_BASE_Y = 14; +const int WAVEFORM_BUTTON_WIDTH = 16; + +const int GENERATOR_BASE_X = 110; +const int GENERATOR_BASE_Y = 24; +const int GENERATOR_BUTTON_WIDTH = 16; + +const int RAND_BUTTON_X = 160; +const int RAND_BUTTON_Y = 4; + +const int MUTA_BUTTON_X = 205; +const int MUTA_BUTTON_Y = 4; + +const int KNOBS_BASE_X = 20; +const int KNOBS_BASE_Y = 50; +const int KNOB_BLOCK_SIZE_X = 40; +const int KNOB_BLOCK_SIZE_Y = 40; + + + + +class sfxrInstrument; + + + +class SfxrSynth +{ +public: + SfxrSynth( const sfxrInstrument * s ); + virtual ~SfxrSynth(); + + void resetSample( bool restart ); + void update( sampleFrame * buffer, const fpp_t frameNum ); + + bool isPlaying() const; + +private: + const sfxrInstrument * s; + bool playing_sample; + int phase; + double fperiod; + double fmaxperiod; + double fslide; + double fdslide; + int period; + float square_duty; + float square_slide; + int env_stage; + int env_time; + int env_length[3]; + float env_vol; + float fphase; + float fdphase; + int iphase; + float phaser_buffer[1024]; + int ipp; + float noise_buffer[32]; + float fltp; + float fltdp; + float fltw; + float fltw_d; + float fltdmp; + float fltphp; + float flthp; + float flthp_d; + float vib_phase; + float vib_speed; + float vib_amp; + int rep_time; + int rep_limit; + int arp_time; + int arp_limit; + double arp_mod; + +} ; + + + +/** + * @brief A class that simplify the constructor of FloatModel, with value [0,1] + */ +class SfxrZeroToOneFloatModel : public FloatModel +{ +public: + SfxrZeroToOneFloatModel(float val, Model * parent): + FloatModel( val, 0.0, 1.0, 0.001, parent) + { + } + /* purpose: prevent the initial value of the model from being changed */ + virtual void loadSettings( const QDomElement& element, const QString& name = QString( "value" ) ) + { + float oldInitValue = initValue(); + FloatModel::loadSettings(element, name); + float oldValue = value(); + setInitValue(oldInitValue); + setValue(oldValue); + } +}; + +/** + * @brief A class that simplify the constructor of FloatModel, with value [-1,1] + */ +class SfxrNegPosOneFloatModel : public FloatModel +{ +public: + SfxrNegPosOneFloatModel(float val, Model * parent): + FloatModel( val, -1.0, 1.0, 0.001, parent) + { + } + /* purpose: prevent the initial value of the model from being changed */ + virtual void loadSettings( const QDomElement& element, const QString& name = QString( "value" ) ) + { + float oldInitValue = initValue(); + FloatModel::loadSettings(element, name); + float oldValue = value(); + setInitValue(oldInitValue); + setValue(oldValue); + } +}; + +class sfxrInstrument : public Instrument +{ + Q_OBJECT +public: + sfxrInstrument(InstrumentTrack * _instrument_track ); + virtual ~sfxrInstrument(); + + virtual void playNote( notePlayHandle * _n, sampleFrame * _working_buffer ); + virtual void deleteNotePluginData( notePlayHandle * _n ); + + virtual void saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + + virtual QString nodeName() const; + + virtual PluginView * instantiateView( QWidget * _parent ); + + void resetModels(); + + +private: + QMutex m_synthMutex; + SfxrZeroToOneFloatModel m_attModel; + SfxrZeroToOneFloatModel m_holdModel; + SfxrZeroToOneFloatModel m_susModel; + SfxrZeroToOneFloatModel m_decModel; + + SfxrZeroToOneFloatModel m_startFreqModel; + SfxrZeroToOneFloatModel m_minFreqModel; + SfxrNegPosOneFloatModel m_slideModel; + SfxrNegPosOneFloatModel m_dSlideModel; + SfxrZeroToOneFloatModel m_vibDepthModel; + SfxrZeroToOneFloatModel m_vibSpeedModel; + + SfxrNegPosOneFloatModel m_changeAmtModel; + SfxrZeroToOneFloatModel m_changeSpeedModel; + + SfxrZeroToOneFloatModel m_sqrDutyModel; + SfxrNegPosOneFloatModel m_sqrSweepModel; + + SfxrZeroToOneFloatModel m_repeatSpeedModel; + + SfxrNegPosOneFloatModel m_phaserOffsetModel; + SfxrNegPosOneFloatModel m_phaserSweepModel; + + SfxrZeroToOneFloatModel m_lpFilCutModel; + SfxrNegPosOneFloatModel m_lpFilCutSweepModel; + SfxrZeroToOneFloatModel m_lpFilResoModel; + SfxrZeroToOneFloatModel m_hpFilCutModel; + SfxrNegPosOneFloatModel m_hpFilCutSweepModel; + + IntModel m_waveFormModel; + + friend class sfxrInstrumentView; + friend class SfxrSynth; +}; + + + +class sfxrInstrumentView : public InstrumentView +{ + Q_OBJECT +public: + sfxrInstrumentView( Instrument * _instrument, + QWidget * _parent ); + + virtual ~sfxrInstrumentView() {}; + +protected slots: + void genPickup(); + void genLaser(); + void genExplosion(); + void genPowerup(); + void genHit(); + void genJump(); + void genBlip(); + void randomize(); + void mutate(); + +private: + virtual void modelChanged(); + + knob * m_attKnob; //Attack Time + knob * m_holdKnob; //Sustain Time + knob * m_susKnob; //Sustain Punch + knob * m_decKnob; //Decay Time + + knob * m_startFreqKnob; //Start Frequency + knob * m_minFreqKnob; //Min Frequency + knob * m_slideKnob; //Slide + knob * m_dSlideKnob; //Delta Slide + knob * m_vibDepthKnob; //Vibrato Depth + knob * m_vibSpeedKnob; //Vibrato Speed + + knob * m_changeAmtKnob; //Change Amount + knob * m_changeSpeedKnob; //Change Speed + + knob * m_sqrDutyKnob; //Squre Duty + knob * m_sqrSweepKnob; //Squre Sweep + + knob * m_repeatSpeedKnob; //Repeat Speed + + knob * m_phaserOffsetKnob; //Phaser Offset + knob * m_phaserSweepKnob; //Phaser Sweep + + knob * m_lpFilCutKnob; //LP Filter Cutoff + knob * m_lpFilCutSweepKnob; //LP Filter Cutoff Sweep + knob * m_lpFilResoKnob; //LP Filter Resonance + knob * m_hpFilCutKnob; //HP Filter Cutoff + knob * m_hpFilCutSweepKnob; //HP Filter Cutoff Sweep + + automatableButtonGroup * m_waveBtnGroup; + pixmapButton * m_sqrWaveBtn; //NOTE: This button has Squre Duty + //and Squre Speed configurable + pixmapButton * m_sawWaveBtn; + pixmapButton * m_sinWaveBtn; + pixmapButton * m_noiseWaveBtn; + + + pixmapButton * m_pickupBtn; + pixmapButton * m_laserBtn; + pixmapButton * m_explosionBtn; + pixmapButton * m_powerupBtn; + pixmapButton * m_hitBtn; + pixmapButton * m_jumpBtn; + pixmapButton * m_blipBtn; + + pixmapButton * m_randomizeBtn; + pixmapButton * m_mutateBtn; + + static QPixmap * s_artwork; +}; + + + +#endif