Skip to content

Commit

Permalink
implemented LFO for the virtual synthesizer. Tested the synthesizer i…
Browse files Browse the repository at this point in the history
…n combiantion with the launchcontrol on the RPi: did not work very well (lot of stutter), as reported elsewhere on internet. On Mac OS X it works fine.
  • Loading branch information
robertoostenveld committed Nov 23, 2015
1 parent f6cdd95 commit fb4b3d2
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 17 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ This repository contains all code for http://www.eegsynth.org.

## Installation instructions for Raspbian

## Installation instructions for Raspbian

Use "raspi-config" to configure the correct keyboard, time-zone,
to extend the partition on the SD card and to disable the automatic
start of the graphical interface upon boot.
Expand Down Expand Up @@ -38,6 +40,12 @@ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/opt/local/lib
sudo apt-get install libportmidi0
sudo apt-get install libportmidi-dev

sudo apt-get install python-pyaudio python3-pyaudio

sudo apt-get install alsa-utils
sudo apt-get install mpg321
sudo apt-get install lame

Note: To use the Launch Control XL with the Raspberry Pi you must
first switch it to low power mode. To do this hold down both the
User and Factory Template buttons and insert the USB cable. Release
Expand Down
4 changes: 2 additions & 2 deletions module/launchcontrol/launchcontrol.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ hostname=localhost
port=6379

[midi]
;device=Launch Control XL ; this is the name on my macbook pro
device=Launch Control XL MIDI 1 ; this is the name on my raspberry pi
device=Launch Control XL ; this is the name on my macbook pro
;device=Launch Control XL MIDI 1 ; this is the name on my raspberry pi

[output]
prefix=launchcontrol
Expand Down
2 changes: 0 additions & 2 deletions module/pulsegenerator/pulsegenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
config.read('pulsegenerator.ini')

r = redis.StrictRedis(host=config.get('redis','hostname'), port=config.getint('redis','port'), db=0)
r.set('foo', 'bar')
r.get('foo')

s = serial.Serial(config.get('serial','device'), config.getint('serial','baudrate'), timeout=3.0)

Expand Down
14 changes: 9 additions & 5 deletions module/synthesizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ The purpose of this module is to provide a simple virtual synthesizer using the

** VCO - voltage controlled oscillator **

The VCO generates a simultaneous triangle, saw and square wave signal, which are mixed into the audio output. It has one input control for the pitch and three input controls for the mixer.
The VCO generates a simultaneous sine-, triangle-, saw- and square-wave signal, which are mixed into the audio output. It has one input control for the pitch and four input controls for the mixer.

** LFO - low frequency oscillator **

The LFO shapes the audio envelope. The LFO has two input controls for the frequency and the depth.

** VCA - voltage controlled amplifier **

The VCA shapes the audio envelope. Each VCA has two input controls for the attenuator and the passthrough level.
The VCA shapes the audio envelope. The VCA has a single input controls for the attenuation.

** ADSR - attack, decay, sustain, release **
** NOT YET IMPLEMENTED: ADSR - attack, decay, sustain, release **

The ADSR takes a trigger as input and generates a continuous envelope as output. It has four input controls.

** VCF - voltage controlled filter **
** NOT YET IMPLEMENTED: VCF - voltage controlled filter **

The filter can be toggled between lowpass, highpass and bandpass filtering of the audio signal. It has two input controls for the frequency and bandwidth.

** Requirements **

The REDIS buffer should be running.
A pair of speakers or headphones should be connected to the raspberry Pi audio output.
A pair of speakers or headphones should be connected to the Raspberry Pi audio output.
15 changes: 8 additions & 7 deletions module/synthesizer/synthesizer.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[general]
name="Synthesizer"
bitrate=16000
bitrate=48000
blocksize=120
taper=linear ; linear or logarithmic

Expand All @@ -13,16 +13,17 @@ sin=0.75
tri=0.00
saw=0.25
sqr=0.00
pitch=1000
vca=1
pitch=64
lfo_frequency=64
lfo_depth=64
vca=64

[input]
sin=launchcontrol.channel00.control077
tri=launchcontrol.channel00.control078
saw=launchcontrol.channel00.control079
sqr=launchcontrol.channel00.control080
pitch=launchcontrol.channel00.control081
vca=launchcontrol.channel00.control053

[output]
channel=left ; left/right/both
lfo_frequency=launchcontrol.channel00.control082
lfo_depth=launchcontrol.channel00.control083
vca=launchcontrol.channel00.control084
30 changes: 29 additions & 1 deletion module/synthesizer/synthesizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,42 @@
control_saw = control_saw/control_total
control_sqr = control_sqr/control_total

################################################################################
# LFO
################################################################################

lfo_frequency = r.get(config.get('input','lfo_frequency'))
if lfo_frequency:
lfo_frequency = float(lfo_frequency)
else:
lfo_frequency = config.getfloat('default','lfo_frequency')
# assume that this value is between 0 and 127
lfo_frequency = lfo_frequency/3

lfo_depth = r.get(config.get('input','lfo_depth'))
if lfo_depth:
lfo_depth = float(lfo_depth)
else:
lfo_depth = config.getfloat('default','lfo_depth')
# assume that this value is between 0 and 127
lfo_depth = lfo_depth/127

################################################################################
# VCA
################################################################################

control_vca = r.get(config.get('input','vca'))
if control_sqr:
if control_vca:
control_vca = float(control_vca)
else:
control_vca = config.getfloat('default','vca')
# assume that this value is between 0 and 127
control_vca = control_vca/127.0

################################################################################
# generate the signal
################################################################################

BUFFER = ''
PERIOD = int(BITRATE/FREQUENCY)
for t in xrange(offset,offset+BLOCKSIZE):
Expand All @@ -91,6 +115,10 @@
wave_saw = control_saw * float(t % PERIOD)/PERIOD
wave_sqr = control_sqr * float((t % PERIOD) > PERIOD/2)
waveform = (wave_sin + wave_tri + wave_saw + wave_sqr)*127
# compose and apply the LFO
control_lfo = (math.sin(math.pi*lfo_frequency*t/BITRATE)+1)/2
control_lfo = lfo_depth + (1-lfo_depth)*control_lfo
waveform = control_lfo * waveform
# apply the VCA
waveform = control_vca * waveform
BUFFER = BUFFER+chr(int(waveform))
Expand Down

0 comments on commit fb4b3d2

Please sign in to comment.