Author |
Message |
rumpofsteelskin
Joined: Apr 22, 2009 Posts: 52 Location: brighton, uk
|
Posted: Fri Mar 17, 2017 4:31 pm Post subject:
simple code resources? |
|
|
I want to start using some more complicated digital stuff, and I remembered I have a teensy lying around! Are there resources where I can find simple code for how to make things like a VCO? Or a filter? I can probably port the code over, doesn't need to be for arduino, just something that demonstrates the idea
I can have a guess at how you might make these things digitally, but having some reference for good / not so good ways of doing them might really speed up the learning process
Specifically, how would you go about making a sine wave VCO? just a lookup table that reads out at different speeds? Seems like a crude approach... |
|
Back to top
|
|
|
blue hell
Site Admin
Joined: Apr 03, 2004 Posts: 24079 Location: The Netherlands, Enschede
Audio files: 278
G2 patch files: 320
|
Posted: Fri Mar 17, 2017 4:51 pm Post subject:
|
|
|
A resource that has been useful to me was musicdsp.org
You could also have a look at the source code for the STK or Chuck .. .which is based on the STK I think.
For sines . there are two approaches I've seen.. the llokup thing .. which is crude maybe but also straightforward .. and a rather elegant solution in like two lines of code based on some clever feedback algorithm. like .. http://musicdsp.org/showone.php?id=166 ... oh thats five lines or so ... but there are other examples of that on the webs too.
Edit: the Alsa modular synth did give me some great ideas too. _________________ Jan
also .. could someone please turn down the thermostat a bit.
|
|
Back to top
|
|
|
rumpofsteelskin
Joined: Apr 22, 2009 Posts: 52 Location: brighton, uk
|
Posted: Fri Mar 17, 2017 5:08 pm Post subject:
|
|
|
ahaa that's great, thankyou, i will check those out throughly.
How do you get a good sine wave if you're reading a lookup table? Do you write the sine to have enough samples to sound good at the lowest frequency you want to play it and then use a timer to queue the next sample -> use the ADC to control the timer?
i am also looking on those resources for the answer but thought I would also ask here for a parallel investigative approach |
|
Back to top
|
|
|
blue hell
Site Admin
Joined: Apr 03, 2004 Posts: 24079 Location: The Netherlands, Enschede
Audio files: 278
G2 patch files: 320
|
Posted: Fri Mar 17, 2017 5:40 pm Post subject:
|
|
|
The sine lookup thing would be phasor based, and in the phasor you'd calculate the frequency stuff, the frequency modulations and the phase modulations ..
A phasor basically is a sawtooth .. so you can use that as an index into a lookup table. But .. as the phasor will give non-integer outputs (or when integer it may have more bits than you'd want to have for the possible indices in the lookup table) you will need interpolation on the sine lookup table.
I could collect some code samples here from what I did, Pascal .. but then again .. all high level languages are a lot like pseudo code. These would be floating point based BTW ... integer based things have some additional considerations.
This may seem clumsy all .. but the advantage is that once you have this in place you can do arbitrary wave form tables. Also the phasor can be used directly to produce a saw oscillator, or with some simple math it will give you tri and square and pwm waves. These will be trivial waveforms then, and they will need some extra calculations to reduce aliasing - but for a sine lookup that is not an issue really. _________________ Jan
also .. could someone please turn down the thermostat a bit.
|
|
Back to top
|
|
|
rumpofsteelskin
Joined: Apr 22, 2009 Posts: 52 Location: brighton, uk
|
Posted: Sat Mar 18, 2017 1:23 am Post subject:
|
|
|
ok - i've used pure data a fair bit so i'm familiar with that idea.
my next question is "how do you write a phasor?" it seems like you would either have some loop which increments a little each time then resets, and you can control the speed by controlling how much it increments each time, or you just read faster or slower through the phasor, in which case, what controls the timing? |
|
Back to top
|
|
|
blue hell
Site Admin
Joined: Apr 03, 2004 Posts: 24079 Location: The Netherlands, Enschede
Audio files: 278
G2 patch files: 320
|
Posted: Sat Mar 18, 2017 4:57 am Post subject:
|
|
|
Ok .. here is some example code doing most of the stuff you'd want to do. This could be simplified a bit of course.
Code: |
// These four functions are used to build a phase lookup table.
type
TSignal = double; // or single will be ok too
const
NOTE_SCALING = 128; // map a 0 - 1 range onto 128 notes
NotesPerOctaveRec = 1.0 / 12.0; // Reciprocal of notes / octave
MiddleNote = 69.0; // Middle A as the reference note
ReferenceA = 440.0; // Frequency for reference A
function UnitsToNoteNumber( const aValue: TSignal): TSignal; inline;
begin
Result := NOTE_SCALING * aValue;
end;
function UnitsToFrequency( const aValue: TSignal): TSignal; inline;
// such that note Nr 69 maps to A 440 Hz
// see: http://www.phys.unsw.edu.au/jw/notes.html
// freq = ( 2 ^ ( notenr - 69) / 12) * 440
// Result := Power( 2, ( aValue - 69) / 12) * ReferenceA;
begin
Result := Power( 2, ( UnitsToNoteNumber( aValue) - MiddleNote) * NotesPerOctaveRec) * ReferenceA;
end;
function FrequencyToPhaseDelta( const aValue: TSignal): TSignal; inline;
begin
Result := aValue * System_Rate_Rec;
end;
function UnitsToPhaseDelta( const aValue : TSignal): TSignal; inline;
begin
Result := FrequencyToPhaseDelta( UnitsToFrequency( aValue));
end;
// Then we have the actual phasor
procedure TModPhasor.DoTick;
var
Trunced: Integer;
begin
// Handle sync - reset to zero
if ( not FOldSync) and SignalToLogic( FInputs[ i_sync])
then FPhase := 0.0;
FOldSync := SignalToLogic( FInputs[ i_sync]);
// Calculate a phase delta based on the frequency and fm inputs
FPhaseDelta := LookupPhaseDelta( FInputs[ i_frequency] + FInputs[ i_freq] + FInputs[ i_fm] * FInputs[ i_fmlevel] + FInputs[ i_cents]);
// Calculate a new phase
FPhase := FPhase + FPhaseDelta;
Trunced := Trunc( FPhase);
FPhase := FPhase - Trunced;
if FPhase < 0
then FPhase := FPhase + 1;
// Handle phase modulation
FPosition := FPhase + Clip( FInputs[ i_phase] * FInputs[ i_pmlevel], -1, 1);
Trunced := Trunc( FPosition);
FPosition := FPosition - Trunced;
if FPosition < 0
then FPosition := FPosition + 1;
// Outputthe current phase value
FOutputs[ o_out] := FPosition;
end;
|
_________________ Jan
also .. could someone please turn down the thermostat a bit.
|
|
Back to top
|
|
|
|