Go Down

Topic: Insert some CC command while the foot controller is sending program changes (Read 682 times) previous topic - next topic

Roberto_

Hi everybody,

I would like to use my arduino uno between the foot controller and the rack units.
The purpose is to send some CC commands (with the code posted here below) to change some parameters in real time on the fxs (and preamp as well), assigning those CC to specific effects.

Is there a way to be sure that I'll never loose a program change command from the foot controller, while injecting those CC into the midi data streaming?

Thanks everybody.

slipstick

I can't see any code and I don't know your "foot controller" or "rack units" or what they do. I guess MIDI is involved because that's what people usually mean by "CC commands".

So with the right code and hardware sending the MIDI messages there's no reason why you should lose any CC or PC messages.

Steve

Grumpy_Mike

Yes a simple MIDI in / out program would enable you to insert your CC messages. If the two messages are sent at the same time then the input message waits in the input buffer until you fish it out and pass it on.

Roberto_

Thanks guys, I hasn't been very clear in posing the question, indeed.

Let me better explain what I have in mind.
As you probably know better than me, every parameter of a rack fx (up to 5 at the same time for my Lexicons) can be patched to a control change. Some of these parameters are just an ON/OFF funcion (0-63 and 64-127), some of them use the entyre range of the midi capabilities (0-127) to change in real time some parameters, like panning, modulation shapes, etc...


I've developed in matlab the code of the signals I want to send as CC:

Code: [Select]
% #1 funzione per Chorus con AM ed FM
fc = 0.29; % Carrier Freq (Hz)
fm = 0.085; % Modulating Signal Freq (Hz)
m = 9; % Modulation Index
t = linspace(0, 10, 2^14); % Number of samples
y = -0.45*sin(2*pi*fc*t*0.96) + 0.45*cos(2*pi*fc*t - (m*sin(2*pi*fm*t))) + 0.1*cos(2*pi*fc*t*2.8);
subplot (3,2,1), plot(t,y);

% #2 funzione per panning
fc = 0.69; % Carrier Freq (Hz)
fm = 0.23; % Modulating Signal Freq (Hz)
m = 9; % Modulation Index
t = linspace(0, 10, 2^14); % Number of samples
y = - 0.5*sin(2*pi*fc*t - (m*cos(2*pi*fm*t*0.618))) + 0.5*cos(2*pi*fc*t*2.8 + (m*sin(2*pi*fm*t*0.618)));
subplot (3,2,2), plot(t,y);

% #3 funzione per psycho-flanger
fc = 0.69; % Carrier Freq (Hz)
fm = 0.23; % Modulating Signal Freq (Hz)
m = 1; % Modulation Index
t = linspace(0, 10, 2^14); % Number of samples
y = - 0.5*sin(2*pi*fc*t - (m*cos(2*pi*fm*t*1.32))) -0.5 + abs(cos(2*pi*fc*t*1.32 + (m*sin(2*pi*fm*t*0.618))));
subplot (3,2,3), plot(t,y);

% #4 funzione per dimensione riverbero
fc = 0.69; % Carrier Freq (Hz)
fm = 0.23; % Modulating Signal Freq (Hz)
m = 19; % Modulation Index
p = 0; %numero del plot
t = linspace(0, 10, 2^14); % Number of samples
y = - 0.6*sin(2*pi*fc*t - (m*cos(2*pi*fm*t*1.32))) + 0.4*cos(2*pi*fc*t*3 - (m*sin(2*pi*fm*t*1.32)));
subplot (3,2,4), plot(t,y);

% #5 funzione per chorus lento
fc = 0.069; % Carrier Freq (Hz)
fm = 0.023; % Modulating Signal Freq (Hz)
m = 19; % Modulation Index
t = linspace(0, 10, 2^14); % Number of samples
y = - abs(sin(2*pi*fc*t - (m*cos(2*pi*fm*t*1.32)))) + abs(cos(2*pi*fc*t*3 - (m*sin(2*pi*fm*t*1.32))));
subplot (3,2,5), plot(t,y);

% #6 funzione per chorus lento
fc = 1.29; % Carrier Freq (Hz)
fm = 0.385; % Modulating Signal Freq (Hz)
m = 18; % Modulation Index
t = linspace(0, 20, 2^14); % Number of samples
y = cos(2*pi*fc*t - (m*sin(2*pi*fm*t*0.26))) ;
subplot (3,2,6), plot(t,y);


and the results are attached.

This is the Matlab code I've developed to see the effect of each parameter in 25 different plots (again attached):

Code: [Select]
% Plot funzioni con AM ed FM
fc = 1.29; % Carrier Freq (Hz)
fm = 0.385; % Modulating Signal Freq (Hz)
m = 9; % Modulation Index
p = 0; %numero del plot
for fi = 0.1:0.04:1.06;
p = p+1;
t = linspace(0, 20, 2^14); % Number of samples
y = cos(2*pi*fc*t - (m*sin(2*pi*fm*t*fi))) + 0.1*cos(2*pi*fc*t*2.8);
subplot(5,5,p), plot(t,y);



Where the basic code is really simple.
I modulate the frequency of a sine or cosine wave by varying the value of the radiants during the time:
Code: [Select]
y = cos(2*pi*fc*t - (m*sin(2*pi*fm*t*0.26)))

This can be splitted in:
Code: [Select]
y = cos(2*pi*fc*t)
That is nothing else than a simple cosine wave of the carrier frequency fc.

Then I modulate the radiants of the funcion, so I change the speed of the radiants, so the frequency.
Code: [Select]
- (m*sin(2*pi*fm*t*0.26))
It's a frequency modulation of the carrier frequency fc at the modulation frequency fm.
The amount of modulation is set by the parameter m.

This is the very basic one, then you can do whatever you want:
- square waves;
- absolute values of the sinewaves;
- odd roots of the sine waves;
- triangular waves;
- sawtooth waves;
- etc...


For example, do you want to do an AM modulation of a FM modulated sine?

Code: [Select]
y = cos(2*pi*am*t) * cos(2*pi*fc*t - (m*sin(2*pi*fm*t))) ;

Where:
- am is the amplitude modulating frequency;
- fm is the frequency modulation frequency.

Roberto_

Can someone please explain me how to do this midi in midi out code in Arduino, to store the program change until the midi is free and then transmit it?

Thanks


Grumpy_Mike

Quote
to store the program change until the midi is free and then transmit it?
You don't have to do anything, it will happen automatically, You use a MIDI libiary to get your MIDI in messages. The libiary will also allow you to define a function that gets done when when each specific message is received. You just set up a function for each message you are expecting and have that function re-transmit the message you receive.

Then your loop function just calls the "have any messages been received" function and also checks your buttons or what ever triggers your messages and if they have been pressed send the appropriate message. During that last bit a MIDI message might arrive but it is automatically stored in the serial input buffer waiting for the "have any messages been received" function to be called.

That said, while that last post detailing modulation techniques is interesting, I don't see how it is relevant to your problem.

Roberto_

Thanks Mike.

What I'm only worried about is that I can loose some data while the Arduino is occupied in sending other data, but if you say it won't happen, that's good.

I will try to sketch a code.

I wrote the matlab code for the following question:
will all the sin and cosin calculations plus the map command to 0-127 take too much time?

Roberto_

Can this basic sketch be a good starting point?
Arent the functions too long to be calculated?

Code: [Select]
void setup() {
  Serial.begin(32150);
  int MidiData = 0;
  int ccNum[5] = {111, 112, 113, 114, 115};
  int ccVal[5] = {0, 0, 0, 0, 0};
  float fc[5] = {1.82, 4.34, 4.34, 4.34, 0.43};
  float fm[5] = {0.53, 0.89, 1.44, 1.91, 0.19};
  int m[5] = {9, 9, 1, 19, 19};
}

void loop() {
  if (Serial.available() > 0) {
    MidiData = Serial.read();
    Serial.write(123);
    Serial.write(MidiData);
  }

  int t = millis();
  ccVal[0] = int (63 * ((- 0.45 * sin(0.96 * fc[0] * t) + 0.45 * cos(fc[0] * t - (m[0] * sin(fm[0] * t))) + 0.1 * cos(fc[0] * t * 2.8)) + 1));
  ccVal[1] = int (63 * ((- 0.5 * sin(fc[1] * t - (m[1] * cos(fm[1] * t))) + 0.5 * cos(fc[1] * t * 2.8 + (m[1] * sin(fm[1] * t)))) + 1));
  ccVal[2] = int (63 * ((- 0.5 * sin(fc[2] * t - (m[2] * cos(fm[2] * t * 1.32))) - 0.5 + abs(cos(fc[2] * t * 1.32 + (m[2] * sin(fm[2] * t * 0.618))))) + 1));
  ccVal[3] = int (63 * ((- 0.6 * sin(fc[3] * t - (m[3] * cos(fm[3] * t))) + 0.4 * cos(fc[3] * t * 3 - (m[3] * sin(fm[3] * t)))) + 1));
  ccVal[4] = int (63 * ((- abs(sin(fc[4] * t - (m[4] * cos(fm[4] * t)))) + abs(cos(fc[4] * t * 3 - (m[4] * sin(fm[4] * t))))) + 1));

  for (cc = 0; cc < 5; cc++); {
    Serial.write(176);
    Serial.write(ccNum[cc]);
    Serial.write(ccVal[cc]);
  }
}

Roberto_

I guess I have to add a code like this one, not to send too much useless data over the midi:

Code: [Select]
if (ccVal[cc] != ccValOld[cc]); {
Serial.write(176);
Serial.write(ccNum[cc]);
Serial.write(ccVal[cc]);
ccValOld[cc] = ccVal[cc];
}

Grumpy_Mike

Quote
Arent the functions too long to be calculated?
It depends on how often they are needed. But if they are being sent to modulate an audio signal then yes.
The trick is to pre-calculate them and stick them in an array, either in storage memory or program memory then you just need to pull them out when you need them.

But I am still not clear what you want to do. It seems like you want to synthersise audio signals on the Arduino, you need something fast for that as well as a lot of pre-calculate tables.

Roberto_

Hello,

the purpose of this code is to generate some variable functions to be transmitted as CC.
Then inside the fx units these CC commands will be patched to specific parameters of the effects (instead of using internal LFOs, or Envelopes, etc..).

So yes, the functions will be calculated continuously.
The easiest way could be to store just one fourth of a sine wave values, and then mirror it for other three fourths and for cosine. Is it something that can save memory and speed-up the calculations?

Taking care that the final values of the equations will be mapped to values from 0 to 127, does it worth to calculate them in float, ora I can speed up the calculations by going to int or double?

Thanks for your help and for any firther suggestion you can give me.

Roberto

Grumpy_Mike

Quote
The easiest way could be to store just one fourth of a sine wave values, and then mirror it for other three fourths and for cosine. Is it something that can save memory and speed-up the calculations?
Yes it is. But you can save time at the expense of memory by encoding the whole wavetable.

Yes you can use fixed point calculations to speed things up, that is use int but treat the numbers as if they were 100 times smaller than they are.

The main problem I see is that you are only going to be able to send these parameters at a rate of about 1KHz or 1000 times a second so that limits the sort of waveform generator they can be. This is just down to the MIDI baud rate.

Roberto_

Thanks again Mike,

I think you intended 100 times bigger than right values, not smaller.
This way the results of a multiplication of two numbers will be within the range -10k and +10k.

So you suggest me to use the PROGMEM&pgm_read duo.
I'm not familiar with it, but I will try.

No worryes for the 1 kHz limit, as they will substitute the LFOs of the rack fx, so we are talking about 0.1-10 Hz most of the time, sometimes 100 Hz. Well, in fact I could calculate one single function each cycle, and update one at a time.

This evening I will update the code, then I will pose you some more questions.

Roberto_

I haven't had time to work on it, but the most logic path seems to store some data for sine, saw, tri, then every 10 loop of the code to calculate one of the values and transmit. There's plenty of time for all the functions.

Thanks for your help Mike!

Go Up