diff --git a/data/themes/default/style.css b/data/themes/default/style.css index a7dc512e9..b9c3e94b1 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -545,24 +545,29 @@ AudioFileProcessorView knob { } organicInstrumentView knob { - color: rgb(205, 16, 216); - qproperty-outerColor: rgb(23, 9, 24); - /*qproperty-outerColor: rgb(64, 21, 67);*/ + color: rgb(124, 207, 98); + qproperty-outerColor: rgb(13, 42, 4); qproperty-innerRadius: 2; - qproperty-outerRadius: 8.7; + qproperty-outerRadius: 7.5; qproperty-centerPointX: 10.5; qproperty-centerPointY: 10.5; - qproperty-lineWidth: 2; + qproperty-lineWidth: 1.5; } +organicInstrumentView knob#harmKnob { + color: rgb(205, 98, 216); + qproperty-outerColor: rgb(18, 4, 18); +} organicInstrumentView knob#fx1Knob, organicInstrumentView knob#volKnob { + color: rgb(157, 157, 157); + qproperty-outerColor: rgb(37, 37, 37); qproperty-innerRadius: 4; - qproperty-outerRadius: 11.2; + qproperty-outerRadius: 10.0; qproperty-centerPointX: 18.5; qproperty-centerPointY: 13.8; - qproperty-lineWidth: 3; + qproperty-lineWidth: 2; } sf2InstrumentView knob { diff --git a/plugins/organic/artwork.png b/plugins/organic/artwork.png index 07c6df140..472e9c2d7 100644 Binary files a/plugins/organic/artwork.png and b/plugins/organic/artwork.png differ diff --git a/plugins/organic/logo.png b/plugins/organic/logo.png index 65478f7a2..da08362d9 100644 Binary files a/plugins/organic/logo.png and b/plugins/organic/logo.png differ diff --git a/plugins/organic/organic.cpp b/plugins/organic/organic.cpp index de05588f3..8464e283a 100644 --- a/plugins/organic/organic.cpp +++ b/plugins/organic/organic.cpp @@ -42,6 +42,8 @@ #include "embed.cpp" + + extern "C" { @@ -62,7 +64,7 @@ Plugin::Descriptor PLUGIN_EXPORT organic_plugin_descriptor = } QPixmap * organicInstrumentView::s_artwork = NULL; - +float * organicInstrument::s_harmonics = NULL; /*********************************************************************** * @@ -90,6 +92,8 @@ organicInstrument::organicInstrument( InstrumentTrack * _instrument_track ) : // Connect events connect( &m_osc[i]->m_oscModel, SIGNAL( dataChanged() ), m_osc[i], SLOT ( oscButtonChanged() ) ); + connect( &m_osc[i]->m_harmModel, SIGNAL( dataChanged() ), + m_osc[i], SLOT( updateDetuning() ) ); connect( &m_osc[i]->m_volModel, SIGNAL( dataChanged() ), m_osc[i], SLOT( updateVolume() ) ); connect( &m_osc[i]->m_panModel, SIGNAL( dataChanged() ), @@ -101,14 +105,37 @@ organicInstrument::organicInstrument( InstrumentTrack * _instrument_track ) : } - m_osc[0]->m_harmonic = log2f( 0.5f ); // one octave below +/* m_osc[0]->m_harmonic = log2f( 0.5f ); // one octave below m_osc[1]->m_harmonic = log2f( 0.75f ); // a fifth below m_osc[2]->m_harmonic = log2f( 1.0f ); // base freq m_osc[3]->m_harmonic = log2f( 2.0f ); // first overtone m_osc[4]->m_harmonic = log2f( 3.0f ); // second overtone m_osc[5]->m_harmonic = log2f( 4.0f ); // . m_osc[6]->m_harmonic = log2f( 5.0f ); // . - m_osc[7]->m_harmonic = log2f( 6.0f ); // . + m_osc[7]->m_harmonic = log2f( 6.0f ); // .*/ + + if( s_harmonics == NULL ) + { + s_harmonics = new float[ NUM_HARMONICS ]; + s_harmonics[0] = log2f( 0.5f ); + s_harmonics[1] = log2f( 0.75f ); + s_harmonics[2] = log2f( 1.0f ); + s_harmonics[3] = log2f( 2.0f ); + s_harmonics[4] = log2f( 3.0f ); + s_harmonics[5] = log2f( 4.0f ); + s_harmonics[6] = log2f( 5.0f ); + s_harmonics[7] = log2f( 6.0f ); + s_harmonics[8] = log2f( 7.0f ); + s_harmonics[9] = log2f( 8.0f ); + s_harmonics[10] = log2f( 9.0f ); + s_harmonics[11] = log2f( 10.0f ); + s_harmonics[12] = log2f( 11.0f ); + s_harmonics[13] = log2f( 12.0f ); + s_harmonics[14] = log2f( 13.0f ); + s_harmonics[15] = log2f( 14.0f ); + s_harmonics[16] = log2f( 15.0f ); + s_harmonics[17] = log2f( 16.0f ); + } for (int i=0; i < m_numOscillators; i++) { m_osc[i]->updateVolume(); @@ -142,8 +169,8 @@ void organicInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) QString is = QString::number( i ); m_osc[i]->m_volModel.saveSettings( _doc, _this, "vol" + is ); m_osc[i]->m_panModel.saveSettings( _doc, _this, "pan" + is ); - _this.setAttribute( "harmonic" + is, QString::number( - powf( 2.0f, m_osc[i]->m_harmonic ) ) ); + m_osc[i]->m_harmModel.saveSettings( _doc, _this, "newharmonic" + is ); + m_osc[i]->m_detuneModel.saveSettings( _doc, _this, "detune" + is ); m_osc[i]->m_oscModel.saveSettings( _doc, _this, "wavetype" @@ -166,6 +193,15 @@ void organicInstrument::loadSettings( const QDomElement & _this ) m_osc[i]->m_detuneModel.loadSettings( _this, "detune" + is ); m_osc[i]->m_panModel.loadSettings( _this, "pan" + is ); m_osc[i]->m_oscModel.loadSettings( _this, "wavetype" + is ); + + if( _this.hasAttribute( "newharmonic" + is ) ) + { + m_osc[i]->m_harmModel.loadSettings( _this, "newharmonic" + is ); + } + else + { + m_osc[i]->m_harmModel.setValue( static_cast( i ) ); + } } m_volModel.loadSettings( _this, "vol" ); @@ -429,26 +465,40 @@ organicInstrumentView::~organicInstrumentView() void organicInstrumentView::modelChanged() { organicInstrument * oi = castModel(); - const float y=91.3; - const float rowHeight = 26.52f; - const float x=53.4; - const float colWidth = 23.829f; // 54.4 77.2 220.2 + + const float y=91.0f; + const float rowHeight = 26.0f; + const float x=53.0f; + const float colWidth = 24.0f; m_numOscillators = oi->m_numOscillators; m_fx1Knob->setModel( &oi->m_fx1Model ); m_volKnob->setModel( &oi->m_volModel ); - // TODO: Delete existing oscKnobs if they exist + if( m_oscKnobs != NULL ) + { + delete[] m_oscKnobs; + } m_oscKnobs = new OscillatorKnobs[ m_numOscillators ]; // Create knobs, now that we know how many to make for( int i = 0; i < m_numOscillators; ++i ) { + // setup harmonic knob + knob * harmKnob = new organicKnob( this ); + harmKnob->move( x + i * colWidth, y - rowHeight ); + harmKnob->setObjectName( "harmKnob" ); + connect( &oi->m_osc[i]->m_harmModel, SIGNAL( dataChanged() ), + this, SLOT( updateKnobHint() ) ); + // setup waveform-knob knob * oscKnob = new organicKnob( this ); oscKnob->move( x + i * colWidth, y ); + connect( &oi->m_osc[i]->m_oscModel, SIGNAL( dataChanged() ), + this, SLOT( updateKnobHint() ) ); + oscKnob->setHintText( tr( "Osc %1 waveform:" ).arg( i + 1 ) + " ", QString() ); // setup volume-knob @@ -473,17 +523,31 @@ void organicInstrumentView::modelChanged() + " ", " " + tr( "cents" ) ); - m_oscKnobs[i] = OscillatorKnobs( volKnob, oscKnob, panKnob, detuneKnob ); + m_oscKnobs[i] = OscillatorKnobs( harmKnob, volKnob, oscKnob, panKnob, detuneKnob ); // Attach to models - m_oscKnobs[i].m_volKnob->setModel( - &oi->m_osc[i]->m_volModel ); - m_oscKnobs[i].m_oscKnob->setModel( - &oi->m_osc[i]->m_oscModel ); - m_oscKnobs[i].m_panKnob->setModel( - &oi->m_osc[i]->m_panModel ); - m_oscKnobs[i].m_detuneKnob->setModel( - &oi->m_osc[i]->m_detuneModel ); + m_oscKnobs[i].m_harmKnob->setModel( &oi->m_osc[i]->m_harmModel ); + m_oscKnobs[i].m_volKnob->setModel( &oi->m_osc[i]->m_volModel ); + m_oscKnobs[i].m_oscKnob->setModel( &oi->m_osc[i]->m_oscModel ); + m_oscKnobs[i].m_panKnob->setModel( &oi->m_osc[i]->m_panModel ); + m_oscKnobs[i].m_detuneKnob->setModel( &oi->m_osc[i]->m_detuneModel ); + } + updateKnobHint(); +} + + +void organicInstrumentView::updateKnobHint() +{ + organicInstrument * oi = castModel(); + for( int i = 0; i < m_numOscillators; ++i ) + { + const float harm = oi->m_osc[i]->m_harmModel.value(); + const float wave = oi->m_osc[i]->m_oscModel.value(); + + m_oscKnobs[i].m_harmKnob->setHintText( tr( "Osc %1 harmonic:" ) + " ", " (" + + HARMONIC_NAMES[ static_cast( harm ) ] + ")" ); + m_oscKnobs[i].m_oscKnob->setHintText( tr( "Osc %1 waveform:" ) + " ", " (" + + WAVEFORM_NAMES[ static_cast( wave ) ] + ")" ); } } @@ -495,6 +559,8 @@ OscillatorObject::OscillatorObject( Model * _parent, int _index ) : m_waveShape( Oscillator::SineWave, 0, Oscillator::NumWaveShapes-1, this ), m_oscModel( 0.0f, 0.0f, 5.0f, 1.0f, this, tr( "Osc %1 waveform" ).arg( _index + 1 ) ), + m_harmModel( static_cast( _index ), 0.0f, 17.0f, 1.0f, + this, tr( "Osc %1 harmonic" ).arg( _index + 1 ) ), m_volModel( 100.0f, 0.0f, 100.0f, 1.0f, this, tr( "Osc %1 volume" ).arg( _index + 1 ) ), m_panModel( DefaultPanning, PanningLeft, PanningRight, 1.0f, @@ -547,10 +613,10 @@ void OscillatorObject::updateVolume() void OscillatorObject::updateDetuning() { - m_detuningLeft = powf( 2.0f, m_harmonic + m_detuningLeft = powf( 2.0f, organicInstrument::s_harmonics[ static_cast( m_harmModel.value() ) ] + (float)m_detuneModel.value() / 100.0f ) / engine::mixer()->processingSampleRate(); - m_detuningRight = powf( 2.0f, m_harmonic + m_detuningRight = powf( 2.0f, organicInstrument::s_harmonics[ static_cast( m_harmModel.value() ) ] - (float)m_detuneModel.value() / 100.0f ) / engine::mixer()->processingSampleRate(); } diff --git a/plugins/organic/organic.h b/plugins/organic/organic.h index 926dce1f1..b4ee15c75 100644 --- a/plugins/organic/organic.h +++ b/plugins/organic/organic.h @@ -2,7 +2,7 @@ * organic.h - additive synthesizer for organ-like sounds * * Copyright (c) 2006-2008 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 @@ -23,8 +23,10 @@ */ -#ifndef _ORGANIC_H -#define _ORGANIC_H +#ifndef ORGANIC_H +#define ORGANIC_H + +#include #include "Instrument.h" #include "InstrumentView.h" @@ -37,6 +39,36 @@ class knob; class NotePlayHandle; class pixmapButton; +const int NUM_HARMONICS = 18; +const QString HARMONIC_NAMES[NUM_HARMONICS] = { + "Octave below", + "Fifth below", + "Fundamental", + "2nd harmonic", + "3rd harmonic", + "4th harmonic", + "5th harmonic", + "6th harmonic", + "7th harmonic", + "8th harmonic", + "9th harmonic", + "10th harmonic", + "11th harmonic", + "12th harmonic", + "13th harmonic", + "14th harmonic", + "15th harmonic", + "16th harmonic" + }; + +const QString WAVEFORM_NAMES[6] = { + "Sine wave", + "Triangle wave", + "Saw wave", + "Square wave", + "Moog saw wave", + "Exponential wave" + }; class OscillatorObject : public Model { @@ -45,11 +77,11 @@ private: int m_numOscillators; IntModel m_waveShape; FloatModel m_oscModel; + FloatModel m_harmModel; FloatModel m_volModel; FloatModel m_panModel; FloatModel m_detuneModel; - float m_harmonic; float m_volumeLeft; float m_volumeRight; // normalized detuning -> x/sampleRate @@ -90,9 +122,10 @@ public: virtual void loadSettings( const QDomElement & _this ); virtual QString nodeName() const; - + int intRand( int min, int max ); + static float * s_harmonics; public slots: void randomiseSettings(); @@ -101,17 +134,17 @@ public slots: private: float inline waveshape(float in, float amount); - + // fast atan, fast rather than accurate inline float fastatan( float x ) { return (x / (1.0 + 0.28 * (x * x))); } - + int m_numOscillators; - + OscillatorObject ** m_osc; - + struct oscPtr { Oscillator * oscLeft; @@ -125,6 +158,8 @@ private: virtual PluginView * instantiateView( QWidget * _parent ); + float m_harmonics [18]; + private slots: void updateAllDetuning(); @@ -144,10 +179,13 @@ private: struct OscillatorKnobs { - OscillatorKnobs( knob * v, + OscillatorKnobs( + knob * h, + knob * v, knob * o, knob * p, knob * dt ) : + m_harmKnob( h ), m_volKnob( v ), m_oscKnob( o ), m_panKnob( p ), @@ -157,7 +195,8 @@ private: OscillatorKnobs() { } - + + knob * m_harmKnob; knob * m_volKnob; knob * m_oscKnob; knob * m_panKnob; @@ -171,8 +210,11 @@ private: pixmapButton * m_randBtn; int m_numOscillators; - + static QPixmap * s_artwork; + +protected slots: + void updateKnobHint(); }; diff --git a/plugins/organic/randomise.png b/plugins/organic/randomise.png index 85518ee52..155d2f1f4 100644 Binary files a/plugins/organic/randomise.png and b/plugins/organic/randomise.png differ diff --git a/plugins/organic/randomise_pressed.png b/plugins/organic/randomise_pressed.png index 00d866ddc..20486f407 100644 Binary files a/plugins/organic/randomise_pressed.png and b/plugins/organic/randomise_pressed.png differ