diff --git a/configure.in b/configure.in index 651279d8c..d40035949 100644 --- a/configure.in +++ b/configure.in @@ -423,12 +423,14 @@ AC_CONFIG_FILES([Makefile plugins/Makefile plugins/audio_file_processor/Makefile plugins/bit_invader/Makefile + plugins/organic/Makefile plugins/plucked_string_synth/Makefile plugins/triple_oscillator/Makefile plugins/vestige/Makefile presets/Makefile presets/AudioFileProcessor/Makefile presets/BitInvader/Makefile + presets/Organic/Makefile presets/PluckedStringSynth/Makefile presets/TripleOscillator/Makefile presets/VeSTige/Makefile diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 707e95dc6..33e6ecfd2 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -2,5 +2,5 @@ if VST_SUPPORT VESTIGE_SUBDIR=vestige endif -SUBDIRS = audio_file_processor bit_invader plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) +SUBDIRS = audio_file_processor bit_invader organic plucked_string_synth triple_oscillator $(VESTIGE_SUBDIR) diff --git a/plugins/organic/Makefile.am b/plugins/organic/Makefile.am new file mode 100644 index 000000000..5b18ca26c --- /dev/null +++ b/plugins/organic/Makefile.am @@ -0,0 +1,32 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/lib -I. + + +AM_CXXFLAGS := $(AM_CXXFLAGS) $(QT_CXXFLAGS) -DPLUGIN_NAME="organic" + + +%.moc: ./%.h + $(MOC) -o $@ $< + + +MOC_FILES = ./organic.moc + +BUILT_SOURCES = $(MOC_FILES) ./embedded_resources.h +EMBEDDED_RESOURCES = $(wildcard *png) + +./embedded_resources.h: $(EMBEDDED_RESOURCES) + $(top_builddir)/buildtools/bin2res $(EMBEDDED_RESOURCES) > $@ + +EXTRA_DIST = $(EMBEDDED_RESOURCES) + + +CLEANFILES = $(MOC_FILES) ./embedded_resources.h + + + +pkglib_LTLIBRARIES= liborganic.la + +liborganic_la_SOURCES = organic.cpp organic.h +$(liborganic_la_SOURCES): ./embedded_resources.h diff --git a/plugins/organic/artwork.png b/plugins/organic/artwork.png new file mode 100644 index 000000000..9904d669e Binary files /dev/null and b/plugins/organic/artwork.png differ diff --git a/plugins/organic/logo.png b/plugins/organic/logo.png new file mode 100644 index 000000000..4f1ca3c86 Binary files /dev/null and b/plugins/organic/logo.png differ diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp new file mode 100644 index 000000000..cc809e844 --- /dev/null +++ b/plugins/organic/organic.cpp @@ -0,0 +1,457 @@ +/* + * bit_invader.cpp - instrument which uses a usereditable wavetable + * + * Copyright (c) 2006 Andreas Brandmaier + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "qt3support.h" + +#ifdef QT4 + +#include +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include +#include +#include "math.h" + +using namespace std; + + +#include "organic.h" +#include "channel_track.h" +#include "note_play_handle.h" +#include "templates.h" +#include "buffer_allocator.h" +#include "knob.h" +#include "pixmap_button.h" +#include "tooltip.h" +#include "song_editor.h" +#include "oscillator.h" +#include "sample_buffer.h" +#include "embed.cpp" +#include "base64.h" + + +extern "C" +{ + +plugin::descriptor organic_plugin_descriptor = +{ + STRINGIFY_PLUGIN_NAME( PLUGIN_NAME ), + "Organic", + QT_TRANSLATE_NOOP( "pluginBrowser", + "Additive Synthesizer for organ-like sounds" ), + "Andreas Brandmaier ", + 0x0100, + plugin::INSTRUMENT, + PLUGIN_NAME::findEmbeddedData( "logo.png" ) +} ; + +} + +QPixmap * organicInstrument::s_artwork = NULL; + + +/*********************************************************************** +* +* class BitInvader +* +* lmms - plugin +* +***********************************************************************/ + + +organicInstrument::organicInstrument( channelTrack * _channel_track ) : + instrument( _channel_track, + &organic_plugin_descriptor ), + specialBgHandlingWidget( PLUGIN_NAME::getIconPixmap( "artwork" ) ) +{ + + + m_num_oscillators = 8; + + m_osc = new oscillatorData[m_num_oscillators]; + + for (int i=0; i < m_num_oscillators; i++) + { + m_osc[i].waveShape = oscillator::SIN_WAVE; + + // setup volume-knob + m_osc[i].volKnob = new knob( knobGreen_17, this, tr( + "Osc %1 volume" ).arg( i+1 ), eng() ); + m_osc[i].volKnob->move( 25+i*20, 90 ); + m_osc[i].volKnob->setRange( 0, 100, 1.0f ); + m_osc[i].volKnob->setValue( 100, TRUE ); + m_osc[i].volKnob->setHintText( tr( "Osc %1 volume:" ).arg( + i+1 ) + " ", "%" ); + + // setup panning-knob + m_osc[i].panKnob = new knob( knobGreen_17, this, + tr( "Osc %1 panning" ).arg( i + 1 ), eng() ); + m_osc[i].panKnob->move( 25+i*20, 110 ); + m_osc[i].panKnob->setRange( PANNING_LEFT, PANNING_RIGHT, 1.0f ); + m_osc[i].panKnob->setValue( DEFAULT_PANNING, TRUE ); + m_osc[i].panKnob->setHintText( tr("Osc %1 panning:").arg( i+1 ) + + " ", "" ); + + // setup knob for left fine-detuning + m_osc[i].detuneKnob = new knob( knobGreen_17, this, + tr( "Osc %1 fine detuning left" ).arg( i+1 ), + eng() ); + m_osc[i].detuneKnob->move( 25+i*20, 130 ); + m_osc[i].detuneKnob->setRange( -100.0f, 100.0f, 1.0f ); + m_osc[i].detuneKnob->setValue( 0.0f, TRUE ); + m_osc[i].detuneKnob->setHintText( tr( "Osc %1 fine detuning " + "left:" ).arg( i + 1 ) + + " ", " " + + tr( "cents" ) ); + + + + } + + // setup knob for FX1 + fx1Knob = new knob( knobGreen_17, this, + tr( "FX1" ), + eng() ); + fx1Knob->move( 20, 160 ); + fx1Knob->setRange( 0.0f, 0.99f, 0.01f ); + fx1Knob->setValue( 0.0f, TRUE ); + + // setup volume-knob + volKnob = new knob( knobGreen_17, this, tr( + "Osc %1 volume" ).arg( 1 ), eng() ); + volKnob->move( 50, 160 ); + volKnob->setRange( 0, 200, 1.0f ); + volKnob->setValue( 100, TRUE ); + volKnob->setHintText( tr( "Osc %1 volume:" ).arg( + 1 ) + " ", "%" ); + + + m_osc[0].harmonic = 0.5f; // one octave below + m_osc[1].harmonic = 0.75f; // a fifth below + m_osc[2].harmonic = 1.0f; // base freq + m_osc[3].harmonic = 2.0f; // first overtone + m_osc[4].harmonic = 3.0f; // second overtone + m_osc[5].harmonic = 4.0f; // . + m_osc[6].harmonic = 5.0f; // . + m_osc[7].harmonic = 6.0f; // . + + + if( s_artwork == NULL ) + { + s_artwork = new QPixmap( PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + } + + + +#ifdef QT4 + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + setPalette( pal ); +#else + setErasePixmap( PLUGIN_NAME::getIconPixmap( "artwork" ) ); +#endif +} + + + +organicInstrument::~organicInstrument() +{ +} + + + + +void organicInstrument::saveSettings( QDomDocument & _doc, + QDomElement & _parent ) +{ + + QDomElement to_de = _doc.createElement( nodeName() ); + + to_de.setAttribute( "num_osc", QString::number( m_num_oscillators ) ); + to_de.setAttribute( "foldback", QString::number( fx1Knob->value() ) ); + to_de.setAttribute( "vol", QString::number( volKnob->value() ) ); + + for( int i = 0; i < m_num_oscillators; ++i ) + { + QString is = QString::number( i ); + to_de.setAttribute( "vol" + is, QString::number( + m_osc[i].volKnob->value() ) ); + to_de.setAttribute( "pan" + is, QString::number( + m_osc[i].panKnob->value() ) ); + to_de.setAttribute( "harmonic" + is, QString::number( + m_osc[i].harmonic ) ); + to_de.setAttribute( "detune" + is, QString::number( + m_osc[i].detuneKnob->value() ) ); + to_de.setAttribute( "wavetype" + is, QString::number( + m_osc[i].waveShape ) ); + } + + + + _parent.appendChild( to_de ); + + +} + + + + +void organicInstrument::loadSettings( const QDomElement & _this ) +{ +// m_num_oscillators = _this.attribute( "num_osc" ). + // toInt(); + + for( int i = 0; i < m_num_oscillators; ++i ) + { + QString is = QString::number( i ); + m_osc[i].volKnob->setValue( _this.attribute( "vol" + is ). + toFloat() ); + m_osc[i].detuneKnob->setValue( _this.attribute( "detune" + is ). + toFloat() ); + m_osc[i].panKnob->setValue( _this.attribute( "pan" + is ). + toFloat() ); + // m_osc[i].waveShape = _this.attribute( "wavetype"+is ).toInt(); + } + + volKnob->setValue( _this.attribute( "vol" ). + toFloat() ); + fx1Knob->setValue( _this.attribute( "foldback" ). + toFloat() ); +} + + +QString organicInstrument::nodeName( void ) const +{ + return( organic_plugin_descriptor.name ); +} + + + + +void organicInstrument::playNote( notePlayHandle * _n ) +{ + if( _n->totalFramesPlayed() == 0 ) + { + float freq = getChannelTrack()->frequency( _n ); + + oscillator * oscs_l[m_num_oscillators]; + oscillator * oscs_r[m_num_oscillators]; + + for( Sint8 i = m_num_oscillators-1; i >= 0; --i ) + { + + // volume + float volume = m_osc[i].volKnob->value() / 100.0 / m_num_oscillators ; + float volume_l = volume * ( m_osc[i].panKnob->value() + + PANNING_RIGHT ) / 100.0f; + float volume_r = volume * ( PANNING_RIGHT - + m_osc[i].panKnob->value() ) / + 100.0f; + + // detuning + float osc_detuning_l = +m_osc[i].detuneKnob->value() / 10.0f; + float osc_detuning_r = -m_osc[i].detuneKnob->value() / 10.0f; + + // frequency + float freq_l = freq * m_osc[i].harmonic + osc_detuning_l; + float freq_r = freq * m_osc[i].harmonic + osc_detuning_r; + + // randomize the phaseOffset [0,360] + int phase_l = (int) (rand() * 360.0); + int phase_r = (int) (rand() * 360.0); + + + + // Nyquist boundary check + if (freq > (eng()->getMixer()->sampleRate() >> 2)) + { + volume = 0; + } + + // initialise ocillators + + if (i == (m_num_oscillators-1)) { + // create left oscillator + oscs_l[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq_l, + phase_l, + volume_l, + eng()->getMixer()->sampleRate() ); + // create right oscillator + oscs_r[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq_r, + phase_r, + volume_r, + eng()->getMixer()->sampleRate() ); + + } else { + // create left oscillator + oscs_l[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq_l, + phase_l, + volume_l, + eng()->getMixer()->sampleRate(), + oscs_l[i + 1] ); + // create right oscillator + oscs_r[i] = oscillator::createOsc( + m_osc[i].waveShape, + oscillator::MIX, + freq_r, + phase_r, + volume_r, + eng()->getMixer()->sampleRate(), + oscs_r[i + 1] ); + + } + + + } + + _n->m_pluginData = new oscPtr; + static_cast( _n->m_pluginData )->oscLeft = oscs_l[0]; + static_cast< oscPtr *>( _n->m_pluginData )->oscRight = + oscs_r[0]; + } + + oscillator * osc_l = static_cast( _n->m_pluginData )->oscLeft; + oscillator * osc_r = static_cast( _n->m_pluginData + )->oscRight; + + const fpab_t frames = eng()->getMixer()->framesPerAudioBuffer(); + sampleFrame * buf = bufferAllocator::alloc( frames ); + + osc_l->update( buf, frames, 0 ); + osc_r->update( buf, frames, 1 ); + + + // -- fx section -- + + // fxKnob is [0;1] + float t = fx1Knob->value() * 5.0f;t++; + + for (int i=0 ; i < frames ; i++) + { + buf[i][0] = distort( buf[i][0], t ) * volKnob->value() / 100.0; + buf[i][1] = distort( buf[i][1], t ) * volKnob->value() / 100.0; + } + + // -- -- + + getChannelTrack()->processAudioBuffer( buf, frames, _n ); + + bufferAllocator::free( buf ); +} + + + + +void organicInstrument::deleteNotePluginData( notePlayHandle * _n ) +{ + if( _n->m_pluginData == NULL ) + { + return; + } + delete static_cast( static_cast( + _n->m_pluginData )->oscLeft ); + delete static_cast( static_cast( + _n->m_pluginData )->oscRight ); + delete static_cast( _n->m_pluginData ); +} + +float organicInstrument::foldback(float in, float threshold) +{ + if (in>threshold || in<-threshold) + { + in= fabs(fabs(fmod(in - threshold, threshold*4)) - threshold*2) - threshold; + } + return in; +} + +float organicInstrument::distort(float in, float dist) +{ + in *= dist; + if (in >= 1.0f) { + return 1.0f; + } else { + return in; + } + +} + +float organicInstrument::saturate(float x, float t) +{ + if(fabs(x) 0.f) + return t + (1.f-t)*tanh((x-t)/(1-t)); + else + return -(t + (1.f-t)*tanh((-x-t)/(1-t))); + } +} + + + +extern "C" +{ + +// neccessary for getting instance out of shared lib +plugin * lmms_plugin_main( void * _data ) +{ + return( new organicInstrument( static_cast( _data ) ) ); +} + + +} + + diff --git a/plugins/organic/organic.h b/plugins/organic/organic.h new file mode 100644 index 000000000..aee1142a6 --- /dev/null +++ b/plugins/organic/organic.h @@ -0,0 +1,106 @@ +/* + * bit_invader.h - declaration of class bitInvader and bSynth which + * are a wavetable synthesizer + * + * Copyright (c) 2006 Andreas Brandmaier + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _ORGANIC_H +#define _ORGANIC_H + + +#ifdef QT4 + +#include + +#else + +#include +#include + +#endif + + +#include "instrument.h" +#include "spc_bg_hndl_widget.h" +#include "led_checkbox.h" +#include "oscillator.h" + +class knob; +class notePlayHandle; +class pixmapButton; + + +class organicInstrument : public instrument, public specialBgHandlingWidget +{ + Q_OBJECT +public: + organicInstrument(channelTrack * _channel_track ); + virtual ~organicInstrument(); + + virtual void FASTCALL playNote( notePlayHandle * _n ); + virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); + + + virtual void FASTCALL saveSettings( QDomDocument & _doc, + QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + + virtual QString nodeName( void ) const; + +private: + + float foldback(float in, float threshold); + float saturate(float x, float t); + float distort(float in, float dist); + + static QPixmap * s_artwork; + + int m_num_oscillators; + + struct oscillatorData + { + oscillator::waveShapes waveShape; + knob * volKnob; + knob * panKnob; + knob * detuneKnob; + float harmonic; + }; + + oscillatorData* m_osc; + + struct oscPtr + { + oscillator * oscLeft; + oscillator * oscRight; + } ; + + knob * fx1Knob; + knob * volKnob; + +} ; + + +#include "organic.moc" + + +#endif