Matrix~ advise on incoroprating

RuthWWWW's icon

Hi,

I'm designing an audio-visual installation/ performance and have made a patch which uses 16 inputs to control filters (granulator, reverb and delay). I'm a newbie and have to a bit confused and need a bit of help figuring out audio inputs (where they are patched to) but also I need help with mixing the audio live as there will potentially be 4 different audio coming in, either recorded directly into the patch or direct just a constant direct feed.

Re: mixing - I know I need to use the matrix~ object but don't know where it goes in the patch. before or after filters.

Atm it's been arranged (for testing) and I've used an audio file to indicate where I want the separate audio to come in but havent included the two other inouts. I don't think I need as many dacs as I have. Everything needs organising better/ simplifying. Please help?!

Max Patch
Copy patch and select New From Clipboard in Max.

RuthWWWW's icon

Ahhh... is this better?

Max Patch
Copy patch and select New From Clipboard in Max.


RuthWWWW's icon

Thanks for the reply. And I've taken on board your comments. Appreciated.

I've just updated my patch although cant seem to scale roomsize for some reason?

  • I will have 3 or 4 analogue inputs (just patched these in - have I done this right though?)

  • 1 comes in is recorded and looped - goes to Reverb

  • 2 comes in is recorded goes to granulator

  • 3 direct input and will go through a filter (haven't done this yet)

  • I do want to add post fader send to reverb, yes.

  • At the moment I've put them through 2 matrix~ for stereo and the matrixctrl~ so I can mix, but might if there's a better way of doing this I'd appreciate feedback as I only really want to mixing the audio together and not worry about bringing in left and right two (if that makes sense?)

Max Patch
Copy patch and select New From Clipboard in Max.

Source Audio's icon

matrix~ has simple logic.

you tell it to send input instance to output instance with set gain.

0 0 1 - means input 0 goes to output 0 with gain 1.

Matrix makes sense in some cases cause it is simple, has ramp time option,etc.

But in some cases one is better off using separate sliders.

sorry, but I get nervous when looking at that big patches with so many waisted space and objects.

here is your initial patch with few changes

Max Patch
Copy patch and select New From Clipboard in Max.

before doing any routing you need to define how do you start/stop recording, from which source etc

P.S.

that reverb (gigaverb ) is also available as external

RuthWWWW's icon

Ok - done this so far -

There will be 3 inputs. Hoping I can use external midi to start/ stop etc

Havent included Matrix yet. sliders to mix/ fade in but I have the basics in previous patch that I hope I can incorporate and again use external midi to control these.

Max Patch
Copy patch and select New From Clipboard in Max.

Thank you so much. Really helping me organise the patches. I think I'm slowly getting there. I know this is probably basic stuff and I've found it complicated but this is after 3 weeks.

Source Audio's icon

here is 4 channel looper, it has overdub , but one can remove it if you want.

it uses fixed 4000 ms length, and buffer named sample.

so take care to remove same buffer name from other patches.

see if it fits to what you need.

one can select a channel or step through, select loop range using top waveform.

We can assign midi controls as you wish later.

instead of 4 mute or solo buttons there is 4 channel multislider.

4chanLooper.maxpat
Max Patch

RuthWWWW's icon

sorry, yes I will assign notes. I think I know how to do this as I have a had a play around with it using the my Novation controller.

Yes all LDRs tested. and working well.

RuthWWWW's icon

Just to let you know I sorted the mixer out. It might not be completely the correct way of mixing multiple audio signals in Max/MSP but this is how I've done it after head scratching :))) It means I cant have a reverb after the mix though.


Source Audio's icon

sweetest pie is self baked one,

even if someone else can pack it nicer ...

I prefer other objects, but you can also look into live.gain~

it is stereo allready and has level meters built in .

Just post if you need any further help.

I detected few connection mistakes in your last patch but maybe you sorted that

allready.

I looked at arduino code ...

It sends string of 16 values no matter if they change or not.

And you have no control of real available range.

If you want to experiment - improve that

let me know. But maybe you have other priorities

RuthWWWW's icon

Your help has been incredible. I appreciate it so much. I was lost before

Re: arduino - I would like to look more closely at this. I was thinking I needed to tweak the range to make it more manageable otherwise they're just going to be everywhere and it will be a cacophony.

I detected few connection mistakes in your last patch but maybe you sorted that

already.

I think I have yes but if you could maybe annotate where these are so I could have look again and see if I got it right. I may have missed something. Its been a steep learning curve and I still have a long way to go but feel much better about Max. I've attached my patch again if you have the time.

And also I'm more than happy to look at alternatives to gain/ live.gain. This all all really positive stuff.

Max Patch
Copy patch and select New From Clipboard in Max.

Source Audio's icon

I am out of the house for a while.

It is good to have updated patch from you.

I will have a look later.

RuthWWWW's icon

No problem. Thank you. Let me know what you think.

Source Audio's icon

back again ...

connections to omx.peaklimiter are wrong...

you should connect stereo output of all live.gain sliders to limiter's stereo input.

check scalers for reverb ... 300 second reverb ???

0.2 - 20 should be more than enough ...

I have again made some work on the patch, in first place packing stuff

into sub patchers to have better GUI.

Reverbs now have have dry/wet mix, so that you can pass dry signal through if you want.

I asked about that a while ago, but you did not decide about dry signal.

added storage for parameters so far.

Max Patch
Copy patch and select New From Clipboard in Max.

RuthWWWW's icon

Thank you so much!!! I ll look at it properly tomorrow. Can’t believe how much you’ve helped me.

RuthWWWW's icon

This is amazing!

I'll play around with it and check:

connections to omx.peaklimiter

scalers for reverb .

Honestly don't know how much I appreciate this it's been a huge help. I've learnt a great deal from you.

I'm working on the installation from next week and the following few weeks (I took a few days off this week - literally maxed out! :))) so I'll let you know how it all goes.

Kindest kindest regards 🙏🏼

Source Audio's icon

you might need help with LDR's as well.

I had no time to really explain all in detail,

but you will need to adjust resistor that forms voltage divider,

depending on type and specs of LDRs that you use.

That 10 kohm shown in most tutorials is a bullshit.

You need to know dark ~ bright light resistance of your LDRs

which differs a lot from type to type, as well as check with what you deal

in installation, then adjust that resistor, and maybe arduino reference voltage.

Only that way one gets most of LDR measurement.

you need only 1 resistor at A0 input on arduino.

All LDRs can be wired directly to multiplexer inputs and +V

Could you post your LDR type and arduino board that you use ?

RuthWWWW's icon

This is really interesting.

ATM I'm using 10ohm on each LDR going into a CD74HC4067 16-CH Analogue Digital MUX Multiplexer

I'm using the Arduino uno r3 but switching this out during installation for the R4 wifi board

I was thinking I'd needed play around with the resistance but ATM its all on a bread board and I haven't protyped it just yet.

I have A0 going into sig on the muliplexer.

Source Audio's icon

LDR can have for example 2 MOhm at total dark and 10Kohm at full light,

like when you place bright LED on top of it.

or 400Kohm / 2 Kohm

etc

There are many different types.

10 Ohm ? how is that going to work ?

LDR resistance together with resistor forms voltage divider.

Or dynamic resistance pot if you want so.


if resistor is 100K and LDR sits at 10 K then you have

5v /110 * 100 = 4.54 v or A0 value 930

in case of 10k resistor it would be 2.5 v or A0 value 512

......

You should measure your LDR's and make simple resistance test

in front of that projector.

One can isolate that many LDRs in room

by placing them into black tubes, to focus light detection as much as possible.

Even filler, or ballpoint pen tube and similar can do.

you will find here info about setting analog reference

for different boards.

that shifts voltage range in order to get full scale sensor readout if sensors can't reach full voltage range.

........

There are other things waiting to be done, like midi control,

You wanted to add another scaler/multislider for filter ?

just post when you need further help.

RuthWWWW's icon

hey. how you doing.

I took a bit of time off.

Just strating to set up installation and mess about with different film projections.

All good except i've come back to the patch and theres no adc~1

seems to be just input through mac microphone. Am I missing something?

Source Audio's icon

adc~ 1 is inside of loop recording bpatcher.

RuthWWWW's icon

thanks, I thought that but I cant seem to access it. need to select the input

RuthWWWW's icon

Also - do you think I should add zl stream, zl median, or slide to smooth out incoming data?

I'm using 100k ohm - works well. Readings range from very low to 1000 so far with projector so tests have gone well so far. Just built a big installation and playing around with film and optical sound input etc. all looking good but just fine tuning now. Swapping out two LDR's but rest work great.

I've had a huge amount of stuff on so had to leave this to one side for a bit.

Just accessed bpatcher btw - sorry

Source Audio's icon

You should first look what you send from Arduino.

I mean in what interval, and if you send only if values changed.

your send 1 list with all LDRs so even if only 1 detects changes to light, you send full list.

How would you smooth that at input ?

One would have to work on outputs in scaler subpatch.

insert change 0. to remove repetitions, and if you still have too fast data

then you can try zl stuff

now it is probably too late to rewrite Arduino Code

RuthWWWW's icon

I've just re-read one of your previous messages

I looked at arduino code ...

It sends string of 16 values no matter if they change or not.

And you have no control of real available range.

If you want to experiment - improve that

let me know.

How can can I change this? is it worth it do you think?

Source Audio's icon

Are you willing to rewrite code short before installation ?

I don't know what I looked at really, you did not post arduino code,

it is only receiving full string that tell's one what is at input.

To do any better, you would need to send individual

LDR values using prepended ID, so that you can route that in max.

More you smooth a list, less responsive is your system.

It all depends how precise you want all to work.

If you have good enough separation between 16 LDR readings,

and enough range to use as control, then you can leave it as is.

And try to ease a bit output of end controls,

in order not to produce too much strain without noticeable effect.

To your question - is it worth ?

sure it is even if only for learning purpose,

but main thing is that you get your installation work in first place.

here is code for you to try :

unsigned long LDR[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

unsigned long exLDR[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

int THRESHOLD = 5; // threshold for "Value Changed" recognition, change as needed

void setup(){analogReference(DEFAULT);

// analogReference(INTERNAL); analogReference(EXTERNAL);

pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); Serial.begin(9600);

}

void loop(){for (int i = 0; i < 16; i++)

{digitalWrite(2,i&0x01); digitalWrite(3,i&0x02); digitalWrite(4,i&0x04); digitalWrite(5,i&0x08);

LDR[i] = analogRead(A0); if(abs(LDR[i] - exLDR[i]) > THRESHOLD)

{Serial.print(i); Serial.print(" ");

Serial.println(LDR[i], DEC); exLDR[i] = LDR[i]; delay(10);}

}}

..............

commented out :

// analogReference(INTERNAL); analogReference(EXTERNAL);

are ther in case you need to adjust it, but as you seem to get enough

at input you can leave it out.

.......

multiplexer pins 2 3 4 5, A0 = input pin

16 inputs get read in a loop and compared with previous reading.

If difference exceeds threshold ( set to 5) output that channel.

you can adjust threshold value to match youtr LDR performance.

IDs range from 0 ~15.

In Max :

RuthWWWW's icon

appreciated. thanks so much i'll try yours out.

I ammeneded my code this morning to this to make it smoother but will try yours too:

// CD74HC4067 pins

const int pinA = 5; // S0

const int pinB = 4; // S1

const int pinC = 3; // S2

const int pinD = 2; // S3


const int analogOutputPin = A0; // Connect to SIG pin of CD74HC4067


unsigned long previousMillis = 0;

const long interval = 10; // Read interval in milliseconds


int previousValues[16] = {0}; // Array to store previous sensor values

const int threshold = 10; // Threshold for detecting significant change

const int numReadings = 10; // Number of readings to average


void setup() {

// Set multiplexer control pins as outputs

pinMode(pinA, OUTPUT);

pinMode(pinB, OUTPUT);

pinMode(pinC, OUTPUT);

pinMode(pinD, OUTPUT);


// Initialize serial communication at 9600 bits per second

Serial.begin(9600);

}


void loop() {

unsigned long currentMillis = millis();


if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

bool dataChanged = false;


// Read values from each LDR

int sensorValues[16];

for (int channel = 0; channel < 16; channel++) {

sensorValues[channel] = averageReadings(channel);

// Check if the sensor value has changed significantly

if (abs(sensorValues[channel] - previousValues[channel]) > threshold) {

dataChanged = true;

}


// Update previous values array

previousValues[channel] = sensorValues[channel];

}


// Send data if any value has changed significantly

if (dataChanged) {

for (int channel = 0; channel < 16; channel++) {

Serial.print(sensorValues[channel]);


// Print a space after each value except the last one

if (channel < 15) {

Serial.print(" ");

}

}

Serial.println();

}

}

}


int averageReadings(int channel) {

int sum = 0;

for (int i = 0; i < numReadings; i++) {

selectChannel(channel);

delay(5); // Small delay to allow the channel to settle

sum += analogRead(analogOutputPin);

}

return sum / numReadings;

}


void selectChannel(int channel) {

digitalWrite(pinA, channel & 1);

digitalWrite(pinB, (channel >> 1) & 1);

digitalWrite(pinC, (channel >> 2) & 1);

digitalWrite(pinD, (channel >> 3) & 1);

}

RuthWWWW's icon

TBH i think i'm overthinking. I think everything is ok -

the sensors work as they should (I think). I think youre right about smoothing things out too much. It's actually quite a simple circuit and I think they key is to know when to stop.

The patch is great thanks to you.

I need to fine tune the film material and installation.

I'm still learning and this has been intense but great. Thanks for all your help.

Source Audio's icon

LDRs are slow themself.

one does not need to average the readings I think.

I would read sensors as fast as possible, but send only ones that

changed > threshold, as in my code.

Then you can deal with result in max.

Source Audio's icon

I don't have that book,

and also I am not really using gen~

RuthWWWW's icon

OK so - I'm very sorry but may need a bit more help.

Everything is great apart from the fact that the projector i'm using runs at24fps (flicker rate of 48) which means that the reading fluctate quite a bit. I've tried adding an 'interval' and calculating the flicker to be 20-30ms but its not really helping.

do I need a capicitor or can I add something in Max or is there another way around this?

Source Audio's icon

Your LDRs have specified rise & fall times. I asked you to post specs or at least model of LDR you use, never got an answer.

24 FPS (41.66 ms) in worst case is toggling black and white screen which is slower then fast LDR

having average 30 ms rise/fall time, again - it depends on LDR type.

If you use one single pull down resistor on Analog Input, there is no way to insert

fast charge / slow discharge RC combination.

Because it would affect all 16 LDRs.

So you either do it 16 times on each input,

or then try something in software, like slide.

RuthWWWW's icon

I'm using LDR Bojack GL5539

100k ohm

I've played around with code and its much better.

Will try maybe change out resistor as the reading with my new projector bulb (otherone blew last week) and averaging 500 rather than full 0 - 1023.

Thanks again. last couple of weeks panic

Heres code.

// Define the pins for the multiplexer control

const int pinA = 5; // S0

const int pinB = 4; // S1

const int pinC = 3; // S2

const int pinD = 2; // S3


const int analogOutputPin = A0; // Connect to SIG pin of CD74HC4067


unsigned long LDR[16] = {0}; // Array to store current LDR readings

unsigned long exLDR[16] = {0}; // Array to store previous LDR readings

int THRESHOLD = 2; // Threshold for "Value Changed" recognition

unsigned long delayTime = 5; // Shorter delay time in milliseconds for real-time responsiveness_maybe remove this if Max isnt responsive

int numReadings = 5; // Number of readings for averaging (higher for more stability)


void setup() {

// Set multiplexer control pins as outputs

pinMode(pinA, OUTPUT);

pinMode(pinB, OUTPUT);

pinMode(pinC, OUTPUT);

pinMode(pinD, OUTPUT);


// Initialize serial communication

Serial.begin(9600);

}


void loop() {

String output = ""; // String to accumulate the output


for (int i = 0; i < 16; i++) {

// Select the channel

selectChannel(i);


// Read the sensor value multiple times and average the results

unsigned long total = 0;

for (int j = 0; j < numReadings; j++) {

total += analogRead(analogOutputPin);

delay(4); // Small delay between readings to stabilize

}

LDR[i] = total / numReadings;


// Add the value to the output string

output += String(LDR[i], DEC) + " ";

}


// Print the accumulated output string

Serial.println(output);


// Delay to slow down the serial monitor output slightly

delay(delayTime);

}


// Function to select the multiplexer channel

void selectChannel(int channel) {

digitalWrite(pinA, channel & 0x01);

digitalWrite(pinB, channel & 0x02);

digitalWrite(pinC, channel & 0x04);

digitalWrite(pinD, channel & 0x08);

}

Source Audio's icon

I know GL5539

bright light can set it at 100KOhm or less, total dark up to 5MOhm.

rise time 20ms, fall time 30 ms, es expected.

You should measure resistance which your projector creates,

get min/max values.

From that one can adjutst resistor value for best result.

If you used 100K resistor , even brightest light can not give you more than

half of analog input range.

You either increase pulldown resistor, adjust analog reference voltage, or scale it in software.

I mentioned all that long time ago.

RuthWWWW's icon

Thank you.

Yes I remember now, you mentioned it a long time ago. I'm sorry. Theres been a lot to take in and so many different elements to the project.

I've scaled in zmap and all good. I dont want to chnage ldr's or resistors because the net bulb/ projector could well be brighter so flexibility to change in max is good.

Thank you.

Source Audio's icon

if you need to tame to fast rise or fall of readings check slide object.

RuthWWWW's icon

OK cool. Would I put this after zmap?

Source Audio's icon

I would place it at the source at input, before any scaling or other manipulation of input.

RuthWWWW's icon

Hey,

Everything is great - cant thank you enough.

I have one very last question and it's just about mapping to midi - it's all mapped but my problem is that Novation launch control XL works but wont light up. I've tried sorting this out and search forums and realise it's something in the patch I need to add but cant seem to do it. It's not ha importnat but would be better for performance if this worked. Please could you advise?

Source Audio's icon

I have no idea what novation unit needs to have lights controlled,

but if you provide enough infos, I'd be very glad to help you out.

I need all midi flow infos that you use in your patch.

And ---- I never use midi mappings.

I use direct CC or notes... whatever, assigned to controls I use.

So can't help you when it comes to that mappings stuff.