summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <florian.a.jung@web.de>2012-04-11 16:36:45 +0200
committerFlorian Jung <florian.a.jung@web.de>2012-04-11 16:36:45 +0200
commit7c875a14b73d844f4f3b8390e4463610262d9415 (patch)
tree915e0023706f3f5a3a81c1707415989dde472bad
parentaec14a264cdb19ccbd9e53596c58da9b60308909 (diff)
added FM-list (brings between 0% and 15% performance improvement)
cast-optimisation programs gets a better operator= commented out segfaulting cleanup()
-rw-r--r--TODO5
-rw-r--r--synth/Makefile2
-rw-r--r--synth/OPTIMIZATIONS14
-rwxr-xr-xsynth/avg_stddev.py27
-rw-r--r--synth/main.cpp2
-rw-r--r--synth/note.cpp41
-rw-r--r--synth/note.h3
-rwxr-xr-xsynth/profile.sh12
-rw-r--r--synth/programs.cpp20
9 files changed, 110 insertions, 16 deletions
diff --git a/TODO b/TODO
index 29f49cc..dffbaf4 100644
--- a/TODO
+++ b/TODO
@@ -6,8 +6,11 @@
!!! SEGFAULT wegen nicht synchronisierter kommunikation bei panic()!
+!!! cleanup() verursacht SEGFAULT, jedenfalls wenn man es durch
+ callgrind laufen lässt
+
TODO für den synth
- o notes kriegen verkettete liste für FM-affect: "kein einfluss"
+ x notes kriegen verkettete liste für FM-affect: "kein einfluss"
steht dann garnicht in der liste (macht aus O(n²) ein O(n))
(macht notencompiler hoffentlich obsolet)
o evtl wieder AM implementieren: hätte hoffentlich dann keinen
diff --git a/synth/Makefile b/synth/Makefile
index 01e27ee..d97ec90 100644
--- a/synth/Makefile
+++ b/synth/Makefile
@@ -1,6 +1,6 @@
CXX=g++
#CFLAGS=-Wall -O2
-CFLAGS=-Wall -O -g
+CFLAGS=-Wall -O3 -g
CXXFLAGS=$(CFLAGS)
LDFLAGS=-lm `pkg-config --cflags --libs jack`
diff --git a/synth/OPTIMIZATIONS b/synth/OPTIMIZATIONS
index 14d5f4f..4a22fd4 100644
--- a/synth/OPTIMIZATIONS
+++ b/synth/OPTIMIZATIONS
@@ -2,6 +2,20 @@ Sinnlose Optimierungen
o if(foo.fm_strength!=0) ...: kein effekt, höchstens leichter anstieg!
Mögliche Optimierungen
+ o ??? if (out>0) und was mit lfo: vlt das if weglassen?
+ o 1% noten kriegen direkten pointer auf ihre waves; (custom_wave-check entfällt)
+ x 15% fm-liste (die nur die oscs mit fm[i]!=0 enthält) statt
+ in O(n²) alle durchzutesten: bei 2 oszillatoren kein effekt,
+ bei 9 oscs der form 1->2->3...->9 (also 9 mod-beziehungen)
+ 17% verbesserung
+ o ??? Channel::get_sample() soll mehrere frames berechnen.
+ soll außerdem das /ONE*VOL_FACTOR gleich mit einrechnen
+ (kann einmalig gleich mit Channel::volume verrechnet werden)
+ o 10% BOTTLENECKs in note.cpp fixen. actual_freq und abhängigkeiten
+ nur dann berechnen, wenn sie sich auch ändert (set_freq, porta,
+ pitchbend, freq-envelope)
+ o ??? log_verbose sollte ggf. garnicht interpretiert werden?
+
o 10% filter ganz auf fixed_t umstellen?
o 5% envelope::get_level nur alle n frames arbeiten lassen, sonst cachen?
o 2% bei LFOs: bei jedem LFO-update die werte für env-max, freqfactor
diff --git a/synth/avg_stddev.py b/synth/avg_stddev.py
new file mode 100755
index 0000000..421a1aa
--- /dev/null
+++ b/synth/avg_stddev.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+import sys
+import math
+
+vals=[]
+sum=0
+cnt=0
+
+for line in sys.stdin:
+ num=float(line)
+ vals.append(num)
+ sum=sum+num
+ cnt=cnt+1
+
+avg=sum/cnt
+
+stddev=0
+for val in vals:
+ stddev=stddev+ (val-avg)**2
+
+stddev=stddev/cnt
+stddev=math.sqrt(stddev)
+
+
+print "avg is " , avg
+print "stddev is " , stddev
diff --git a/synth/main.cpp b/synth/main.cpp
index 95a6a7b..5427b75 100644
--- a/synth/main.cpp
+++ b/synth/main.cpp
@@ -199,7 +199,7 @@ int main(int argc, char** argv)
do_in_synth_cli();
- cleanup();
+ //cleanup();
}
catch(string err)
{
diff --git a/synth/note.cpp b/synth/note.cpp
index 54267a8..f468a79 100644
--- a/synth/note.cpp
+++ b/synth/note.cpp
@@ -50,6 +50,11 @@ Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int pr
copy(&prg.osc_settings[0],&prg.osc_settings[n_oscillators],oscillator);
copy(&prg.osc_settings[0],&prg.osc_settings[n_oscillators],orig.oscillator);
+ fm_oscs=new list<int>[n_oscillators];
+ for (int i=0;i<n_oscillators;++i)
+ for (int j=0;j<n_oscillators;++j)
+ if (oscillator[i].fm_strength[j]!=0)
+ fm_oscs[i].push_back(j);
//initalize oscillator.phase to multiples of their wave resolution
//this has the following effect: the actual phase, i.e. the index
@@ -156,8 +161,13 @@ void Note::apply_pfactor()
oscillator[i].output=orig.oscillator[i].output*pfactor.out[i] >>SCALE;
oscillator[i].freq_env_amount=orig.oscillator[i].freq_env_amount*pfactor.freq_env_amount[i] /ONE; //because it's a float
+ fm_oscs[i].clear();
for (int j=0;j<n_oscillators;++j)
+ {
oscillator[i].fm_strength[j]=orig.oscillator[i].fm_strength[j]*pfactor.fm[i][j] >>SCALE;
+ if (oscillator[i].fm_strength[j]!=0)
+ fm_oscs[i].push_back(j);
+ }
}
filter_params.env_amount=orig.filter_params.env_amount*pfactor.filter_env /ONE;
filter_params.freqfactor_offset=orig.filter_params.freqfactor_offset*pfactor.filter_offset /ONE;
@@ -321,7 +331,7 @@ fixed_t Note::get_sample()
if (freq!=dest_freq)
{
// the div.by.zero if p_frames=0 is avoided because then the
- // if-condition below is always true
+ // if-condition below would always be true
if (portamento_t>=portamento_frames)
freq=dest_freq;
else //will only happen if p_t < p_frames -> p_frames is always > 0 -> div. ok
@@ -342,11 +352,16 @@ fixed_t Note::get_sample()
fixed_t fm=0;
fixed_t out=0;
- int i,j;
+ int i;
if (sync_factor)
{
- sync_phase+=(actual_freq*sync_factor/samp_rate) >> SCALE;
+ sync_phase+=(actual_freq*sync_factor/samp_rate) >> SCALE; // BOTTLENECK
+ // phase-increment depends on:
+ // - actual_freq (which depends on freq and pitchbend)
+ // steadily updated while portamento-ing and whenever a pitchbend comes in
+ // - sync_factor: only updated manually
+ // - samp_rate: never changes
if (sync_phase >= ONE)
{
@@ -382,9 +397,9 @@ fixed_t Note::get_sample()
{
fm=0;
- for (j=0;j<n_oscillators;++j)
- if (oscillator[i].fm_strength[j]!=0) //osc_j affects osc_i (FM)
- fm+=old_oscval[j]*oscillator[i].fm_strength[j];
+ //iterate through all modulating oscs
+ for (list<int>::iterator j=fm_oscs[i].begin(), end=fm_oscs[i].end(); j!=end; j++)
+ fm+=old_oscval[*j]*oscillator[i].fm_strength[*j];
fm=fm>>SCALE;
@@ -392,18 +407,26 @@ fixed_t Note::get_sample()
if (oscillator[i].vibrato_depth!=0)
oscillator[i].phase+=( (curr_lfo[oscillator[i].vibrato_lfo][oscillator[i].vibrato_depth]*actual_freq >>SCALE)*oscillator[i].factor/samp_rate)>>SCALE;
else
- oscillator[i].phase+=(actual_freq*oscillator[i].factor/samp_rate)>>SCALE;
+ oscillator[i].phase+=(actual_freq*oscillator[i].factor/samp_rate)>>SCALE; // BOTTLENECK
+ // phase-increment depends on:
+ // - actual_freq (which depends on freq and pitchbend)
+ // steadily updated while portamento-ing and whenever a pitchbend comes in
+ // - the vibrato-lfo: needs update whenever this lfo is updated
+ // - factor (which depends on the freq envelope)
+ // steadily updated every env_frames frames
+ // - samp_rate: never changes
if (oscillator[i].custom_wave)
{
//sampler
custom_wave_t *cw=oscillator[i].custom_wave;
- oscval[i]=cw->wave[ ((oscillator[i].phase + fm) * cw->samp_rate >>(2*SCALE)) % cw->wave_len ] * envval[i] >> (SCALE);
+ oscval[i]=cw->wave[ ((unsigned int)((oscillator[i].phase + fm) * cw->samp_rate >>(2*SCALE))) % cw->wave_len ] * envval[i] >> (SCALE);
}
else
{
//normal oscillator
- oscval[i]=wave[oscillator[i].waveform][ ((oscillator[i].phase + fm) * WAVE_RES >>SCALE) % WAVE_RES ] * envval[i] >> (SCALE);
+ //optimisation: the unsigned int cast avoids a slow 64bit modulo calculation. ca. 8% speed gain. same above.
+ oscval[i]=wave[oscillator[i].waveform][ ((unsigned int)((oscillator[i].phase + fm) * WAVE_RES >>SCALE)) % WAVE_RES ] * envval[i] >> (SCALE);
}
if (oscillator[i].tremolo_depth!=0)
diff --git a/synth/note.h b/synth/note.h
index 7181f6d..379f2b1 100644
--- a/synth/note.h
+++ b/synth/note.h
@@ -3,6 +3,8 @@
#include <jack/jack.h>
+#include <list>
+
#include "programs.h"
#include "envelope.h"
#include "fixed.h"
@@ -43,6 +45,7 @@ class Note : public NoteSkel
fixed_t *old_oscval;
int n_oscillators;
oscillator_t *oscillator;
+ std::list<int>* fm_oscs;
fixed_t sync_factor;
fixed_t sync_phase;
diff --git a/synth/profile.sh b/synth/profile.sh
new file mode 100755
index 0000000..921a5d4
--- /dev/null
+++ b/synth/profile.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+if [ x$1 = x ]; then
+ cnt=5
+else
+ cnt=$1
+fi
+
+for ((i=1;i<=$cnt;i++)); do
+ /usr/bin/time -p ./synth -p 0:analog.prog -i 60 -x 1000:1 -a -m 2>&1 | grep 'user ' | sed 's/user //';
+ #echo "$i / $cnt done" 1>&2
+done | python avg_stddev.py
diff --git a/synth/programs.cpp b/synth/programs.cpp
index 5dae4ed..63078c0 100644
--- a/synth/programs.cpp
+++ b/synth/programs.cpp
@@ -26,15 +26,27 @@ oscillator_t& oscillator_t::operator=(const oscillator_t &that)
{
if (this!=&that)
{
+ this->output=that.output;
+ this->waveform=that.waveform;
+ this->factor=that.factor;
+ this->freq_env_amount=that.freq_env_amount;
+ this->freq_env=that.freq_env;
+ this->phase=that.phase;
+ this->tremolo_depth=that.tremolo_depth;
+ this->tremolo_lfo=that.tremolo_lfo;
+ this->vibrato_depth=that.vibrato_depth;
+ this->vibrato_lfo=that.vibrato_lfo;
+ this->custom_wave=that.custom_wave;
+ this->n_osc=that.n_osc;
+ this->ksl=that.ksl;
+ this->ksr=that.ksr;
+ this->sync=that.sync;
+
if (this->fm_strength)
delete [] this->fm_strength;
- memcpy(this, &that, sizeof(*this));
-
this->fm_strength=new fixed_t[n_osc];
memcpy(this->fm_strength, that.fm_strength, sizeof(*that.fm_strength)*n_osc);
-
- this->custom_wave=that.custom_wave;
return *this;
}