3-op FM synth with mod matrix
@djpersonalspace Thanks for sharing the patch you're working on. I should point out that your patch uses "real" FM, which means that you directly modulate the frequency of an osc~, whereas my patch (like most implementations of FM) uses what is called "phase modulation", where you modulate the phase lookup of a sine wave instead. This is a key difference to understand if you are trying to implement multi-operator FM.
For the basics on this, have a look at help > browser > pure data > 3.audio.examples > E08.phase.mod.pd
This is what my mod matrix is doing in the patch, there is one table which holds the phase of each operator, and every time some other operator is sent to modulate it by some amount (aka the modulation index), the output of this modulator is added to the table along with all the others that are set to modulate it. I think that once you understand the difference between FM and PM this becomes clearer.
You could do all this in a simpler way with s~, r~, throw~ and catch~. The reason I'm doing all this madness with tables here is because I wanted to have feedback as well for each operator, and in order to do so the phases need to be updated sample by sample, whereas s~ and r~ objects only work in chunks of 64 samples. That doesn't sound right when you try it.
lua markov generator
i build a lua markov generator inspired from this python code with the idea to use it with pure data / ofelia: https://eli.thegreenplace.net/2018/elegant-python-code-for-a-markov-chain-text-generator/
finally the code works fine with the eclipse lua ide or with this ide https://studio.zerobrane.com/, but somehow not yet with pure data / ofelia.
here is the (not yet working) patch: ofelia_markov.pd
and here the lua code: markov_pd.lua
math.randomseed(os.time()- os.clock() * 1000);
-- make dictionary;
function defaultdict(default_value_factory);
local t = {};
local metatable = {};
metatable.__index = function(t, key);
if not rawget(t, key) then;
rawset(t, key, default_value_factory(key));
end;
return rawget(t, key);
end;
return setmetatable(t, metatable);
end;
;
;
-- make markov matrix;
print('Learning model...')
;
STATE_LEN = 3;
print ("markov order: " , STATE_LEN)
model = defaultdict(function() return {} end)
data = "00001111010100700111101010000005000700111111177111111";
datasize = #data;
print("data: ", data);
print("datasize: ", #data);
data = data .. data:sub(1, STATE_LEN);
print("altered data: ", data);
print("altered datasize: ", #data);
for i = 1, (#data - STATE_LEN) do;
state = data:sub(i, i + STATE_LEN-1);
-- print("state: ", state)
local next = data:sub(i + STATE_LEN, i + STATE_LEN);
-- print("next: ", next);
model[state][next] = (model[state][next] or 0)+1;
end;
;
;
-- make markov chain;
print('Sampling...');
;
local keyTbl = {};
local nexTbl = {};
local prbTbl = {};
for key, value in pairs(model) do;
for k, v in pairs(value) do;
table.insert(keyTbl, key);
table.insert(nexTbl, k);
table.insert(prbTbl, v);
end;
end;
print ("keyTbl: ", table.unpack(keyTbl));
print ("nexTbl: ", table.unpack(nexTbl));
print ("prbTbl: ", table.unpack(prbTbl));
;
;
-- make random key;
local randomKey = keyTbl[math.random(#keyTbl)];
state = randomKey;
print("RandomKey: ", randomKey);
;
-- make table from random key;
local str = state;
local stateTable = {};
for i = 1, #str do;
stateTable[i] = str:sub(i, i);
end;
;
out = stateTable;
print ("random key as table: ", table.unpack(out));
;
-- make markov chain;
for i = 1, datasize do;
;
-- weighted random choices;
local choices = {};
local weights = {};
for j = 1, #keyTbl do;
if state == keyTbl[j] then;
table.insert(choices, nexTbl[j]);
table.insert(weights, prbTbl[j]);
end;
end;
-- print ("choices:",table.unpack(choices));
-- print ("weights:",table.unpack(weights));
;
local totalWeight = 0;
for _, weight in pairs(weights) do;
totalWeight = totalWeight + weight;
end;
rand = math.random() * totalWeight;
local choice = nil;
for i, weight in pairs(weights) do;
if rand < weight then;
choice = choices[i];
choice = choice:sub(1,1);
break;
else;
rand = rand - weight;
end;
end;
;
table.insert(out, choice);
state = string.sub(state, 2, #state) .. out[#out];
-- print("choice", choice);
-- print ("state", state);
end;
;
print("markov chain: ", table.concat(out));
somehow pure data / ofelia interprets the nexTbl values as a functions while they are strings?
this is part of what the pure data console prints: nexTbl: function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30
ofelia: [string "package.preload['#d41b70'] = nil package.load..."]:93: attempt to index a function value (local 'choice')
and this ist the output from the lua ide:
Program 'lua.exe' started in 'C:\Users\Jonat\Downloads\ZeroBraneStudio\myprograms' (pid: 220).
Learning model...
markov order: 1
data: 00001111010100700111101010000005000700111111177111111
datasize: 53
altered data: 000011110101007001111010100000050007001111111771111110
altered datasize: 54
Sampling...
keyTbl: 5 7 7 7 1 1 1 0 0 0 0
nexTbl: 0 0 1 7 7 1 0 5 7 1 0
prbTbl: 1 2 1 1 1 17 7 1 2 7 13
RandomKey: 1
random key as table: 1
markov chain: 111111000077701111100070001100000001100017011171111117
Program completed in 0.06 seconds (pid: 220).
Ofelia Jump On Click Slider
@cuinjune thanks. i am sure the overlapping problem is solvable, i think i need to change the mouse behaviour of the gui templates (for me) for that case. i am also quite positive with the results so far, and motivated to try further. somehow i needed to change every loadbang to ofWindowLoadBang to make the dynamic patching work (?). now it makes really sense, like you mentioned earlier, to think about a concept i have some ideas, but what i definitely would like is if everybody could put their own modules easily inside kind of a template and connect them with others. also if there should be something like a main mixer or sequencer is a question for me. or if i want a "reason like" rack or more like a modular interface or something else. also saving is a good question. it would be nice if it is possible to save globally and locally, so that there are presets for a global setting that can also save the local settings of the modules. saving them as patches sounds like a good idea. i think about four module categories: instruments, effects, sequencer and visualizer or something between them. and analog to pure data, it would make sense to have audio and control connections seperated. i think more difficult than creating and destroying modules with dynamic patching is creating cord connections with dynamic patching, but perhaps also solvable because there is a fixed number of objects in every module. so maybe, theoretically one just needs the module id and the module and input output number and then it could work with the connect and disconnect message. i am not sure if i think too far with the concept, the initial idea was more to create some modules, connect them and see what happens
Ofelia Jump On Click Slider
@Jona Looks great! Yes it should be possible. But I think you would need to replace [ofTouchListener] with [_locRcv]s to listen to the event from the main patch so the module interface can listen to the mouse click according to the render order. (Just like how it's done with draggableShapes example)
[_locRcv] should be used one level lower from the main patch. This is to use main patch's local variable name and still communicate with other abstractions. Also note if you use [ofMouseListener], it will not handle multitouch on mobile devices. (it will respond to one finger at a time) That's why I used [ofTouchListener] in pdgui abstraction. But if you're targeting desktop only, [ofMouseListener] is enough and easier to handle.
If you really want to build the modular environment using multiple modules, I suggest you first consider how each module should work commonly and try to first build a minimal module that only has common attributes. (e.g. window bar, interface section, render order..) Then it would be easier to maintain and to create other module later on since you only need to add the non-common part on top of your minimal module.
I think creating such large system requires thorough planning and clear idea of how things should work in the first place otherwise it is likely that you will continuously face many unexpected problems and have to rework many times.
P.S.: You probably know this but your patch currently uses left audio channel only.
Ofelia Jump On Click Slider
@Jona Hi, I just added the feature to [numbox] as it didn't sound too difficult to implement one. numbox.pd
Thank you for your suggestion. I will add this change officially once it seems to be working stably. Let me know if you find any problem using it.
It is not possible(and won't be anytime soon) to continue the audio stream while resizing the window. What you can do instead is using the hotkey Ctrl -/+ which also resizes the window.
Creating draggable and patchable synth modules sounds very interesting although it will be a huge amount of work. Maybe you're thinking something like a Nord Modular or a Reaktor? I also once thought about creating a patchable environment in ofelia via dynamic patching. But there will be so many problems to solve like how to accurately keep track of objects and connections, how to deal with patch saving and loading and so on.. But I'm still keen on finding the good solution.
It will be a lot easier if you allow users to create a limited number of modules so you don't have to dynamically create/destroy modules and each module can have its own unique ID so you can make a connection using it. And even easier if you have a fixed number of modules like Korg MS-20 since you only need to deal with connections of patch cords and parameters of the module. And the easiest would be to create something like a groovebox or a synth which has a fixed internal connection and all you need is to handle the existing parameters.
Thanks for reminding me this. I will think about the ways to create patchable environment again soon. (although there's no guarantee of finding the solution)
PdModular
So I'm working on a project right now and I'm interested in getting some input on the project as I'd like to open source it when I finish. Its a similar idea to the Nord modular but implemented in PD, Python and C. I will try to keep this up to date as the project continues and if there is interest I would be happy to upload some of the code to git
Parts:
Python GUI for building synthesizer utilizing pyata and tkinter
PD objects for each module(VCO, VCA, ENV, MIX, VCF, MIDI, OUTPUT)
Raspberry Pi Cluster(1 conductor and 4 voices) connected via an ethernet switch a d voices ran through a passive mixer
C program for converting midi to OSC messages and sending them to each voice for polyphony as well as uploading your patch of choice
The main idea is that you build a synthesizer patch in the GUI which runs on the conductor which is converted to a PD patch. This patch is then chosen on the conductor raspberry pi when in play mode and is distributed to the 4 voice raspberry pi. All pi's are connected through a switch. This signal for each voice is sent through a passive 4 channel stereo mixer which is sent to a speaker or headphones. A midi controller is plugged into the conductor via usb and its knobs/sliders can be mapped to slider objects within the patch
Adding Modules:
A module consists of a pd object and a python array that represents the inputs and outputs and generates the module object within the application. This will allow for the simple addition of new modules as long as they adhere to the input and output specifications. I hope to add substantially more modules once I get the minimal set needed to build a basic synthesizer.
Would people be interested in something like this at all?
DIY2 - Effects, Sample players, Synths and Sound Synthesis.
@mod said:
>>another suggestion: why not make a lib sub-folder. where you can store such things like modulate. or a scale log which then could work with arguments. <<
that's how i originally did it, but i just wanted to make it so that the modules would just 'work' even if they were removed from the library. i guess i was kind of successful in that regard, because i have spotted some of my drums and stuff inside other people's projects. the only abstraction they need is the 808_state for state saving, but they will work fine without that anyway.
>>currently i guess it would be annoying to change all modulates.<<
i sometimes have a lot of free time
the other day i went through the whole library and replaced all the [loadbang] objects with a subpatch to allow for loadbang on dynamic creation. this meant changing around 100 patches and resaving them.
i will do DIY3 soon then. it is not 'finished', and i have some worries that it is not at all backwards compatible with DIY2, but at the end of the day i am a musician more than a programmer, so the function is what matters.
diy3 'upgrades' include:
a built in sound editor, so you can record loops and sounds and edit them within pd and then export them to .wav files.
some more 'synth' like modules and effects units (tape echo, etc)
inbuilt diy-clock module that ties everything together for sequencing, and then of course some sequencer modules.
vanilla pd compatibility (this unfortunately meant removing some really useful things like the 7 and 13 band EQ's, but they could always be imported from DIY2)
Hello,
I happen to be researching ways to make a tape echo like the old roland type using pure data. Would it be possible for you to put up some of the effects from DIY3 such as the tape echo you mentioned?
Beatmaker Abstract
http://www.2shared.com/photo/mA24_LPF/820_am_July_26th_13_window_con.html
I conceptualized this the other day. The main reason I wanted to make this is because I'm a little tired of complicated ableton live. I wanted to just be able to right click parameters and tell them to follow midi tracks.
The big feature in this abstract is a "Midi CC Module Window" That contains an unlimited (or potentially very large)number of Midi CC Envelope Modules. In each Midi CC Envelope Module are Midi CC Envelope Clips. These clips hold a waveform that is plotted on a tempo divided graph. The waveform is played in a loop and synced to the tempo according to how long the loop is. Only one clip can be playing per module. If a parameter is right clicked, you can choose "Follow Midi CC Envelope Module 1" and the parameter will then be following the envelope that is looping in "Midi CC Envelope Module 1".
Midi note clips function in the same way. Every instrument will be able to select one Midi Notes Module. If you right clicked "Instrument Module 2" in the "Instrument Module Window" and selected "Midi input from Midi Notes Module 1", then the notes coming out of "Midi Notes Module 1" would be playing through the single virtual instrument you placed in "Instrument Module 2".
If you want the sound to come out of your speakers, then navigate to the "Bus" window. Select "Instrument Module 2" with a drop-down check off menu by right-clicking "Inputs". While still in the "Bus" window look at the "Output" window and check the box that says "Audio Output". Now the sound is coming through your speakers. Check off more Instrument Modules or Audio Track Modules to get more sound coming through the same bus.
Turn the "Aux" on to put all audio through effects.
Work in "Bounce" by selecting inputs like "Input Module 3" by right clicking and checking off Input Modules. Then press record and stop. Copy and paste your clip to an Audio Track Module, the "Sampler" or a Side Chain Audio Track Module.
Work in "Master Bounce" to produce audio clips by recording whatever is coming through the system for everyone to hear.
Chop and screw your audio in the sampler with highlight and right click processing effects. Glue your sample together and put it in an Audio Track Module or a Side Chain Audio Track Module.
Use the "Threshold Setter" to perform long linear modulation. Right click any parameter and select "Adjust to Threshold". The parameter will then adjust its minimum and maximum values over the length of time described in the "Threshold Setter".
The "Execution Engine" is used to make sure all changes happen in sync with the music.
IE>If you selected a subdivision of 2, and a length of 2, then it would take four quarter beats(starting from the next quarter beat) for the change to take place. So if you're somewhere in the a (1e+a) then you will have to wait for 2, 3, 4, 5, to pass and your change would happen on 6.
IE>If you selected a subdivision of 1 and a length of 3, you would have to wait 12 beats starting on the next quater beat.
IE>If you selected a subdivision of 8 and a length of 3, you would have to wait one and a half quarter beats starting on the next 8th note.
http://www.pdpatchrepo.info/hurleur/820_am,_July_26th_13_window_conception.png
JKP - Bangboum
Sorry I'm getting errors, can you help me?
I've installed the montreal mtl library, but still I have too many objects missing
mtl/qompander~ /id compander
... couldn't create
mtl/clkMaster 120
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
[msgfile] part of zexy-2.2.3 (compiled: Sep 22 2010)
Copyright (l) 1999-2008 IOhannes m zmölnig, forum::für::umläute & IEM
mtl/player~
... couldn't create
mtl/clkSlave 4 16
... couldn't create
mtl/kick808~
... couldn't create
mtl/clkSlave 1 4
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
setting pattern to default: /home/leopard/Documenti/Music/_sperimentazioni/_PURE DATA/Bangboum/./moteur/*
mtl/player~
... couldn't create
Recreating analogue valve compressor in PD
It will probably be a waste of time trying to faithfully model the compressor in Pd, it's easy to create a simple compressor, but what you need to do is physically model the circuitry. This will mean all the non-linearities present in the circuit will be recreated, and the compressor will sound like a real analogue compressor. I wanted to model analogue filters in Pd, but it can't be done, what people have done in the past is written them in C and compiled them into externals.
That's if you wanted to do a realistic imitation of it, which for a uni project I assume you would want to do. Analogue modeling is a difficult one, I just completed a uni project on physical modeling of a guitar using Pd and I wanted to model a Moog filter to pass the guitar signal through, but I can't write in C.
Actually, I remember reading a thesis where someone modeled the tone controls of a guitar in C, and to get a difference equation for a filter they built the circuit in SPICE, which is freeware for PC, but there is a Mac version. Once you build the circuit it plots graphs of the output, and you can swap around components. I don't know if that's any help, but it could be a start seeing as I assume you built it yourself so will have the circuit diagrams for it.