Implementing MIDI Control Change for “Tsunami Wav Trigger”?

I have a “Tsunami Wav Trigger” working with a modified example Arduino “MIDI note player” sketch, this has been modified so the MIDI Bank Number is changed by using the MIDI Program Change message.
The “Tsunami User Guide – robertsonics” says that the board responds to Controller messages for real-time control of attack and release times. Using CC#73: Attack Time (0 – 2000ms) and CC#72: Release Time (0 – 2000ms).
I wish to implement attack and release to all the noteOn and noteOff commands so the volume of note will ramp up or down over a specified time.
Can you please help me with my code? I attach a copy below.

#include 
void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);

}
int CurrentMidiBank = 1;
int CurrentMidiChannel= 0;

void loop() {

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for( int bank= 0; bank < 4; bank ++ )
  {
    CurrentMidiBank= bank;
    midiBank( CurrentMidiChannel, CurrentMidiBank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    // for (int note = 0x1E; note < 0x5A; note ++)
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( CurrentMidiChannel, note, 0x45);
      delay(500);

      noteOff( CurrentMidiChannel, note, 0x00);
      delay(500);   
    }
  
    delay( 1500 );
  }  
}
// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:
// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:
// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte volume) 
{
  midiMsg( (0x80 | channel), note, volume );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
    Serial.write(cmd);
    Serial.write(data1);
    Serial.write(data2);
}

So you need a control change message for 73 and 72 sent whenever you want to set the relevant
parameters.

The bytes will be
0xBn, 0x48,
0xBn, 0x49,

For channel n+1. So channel 1 would be 0xB0,0x48,

Am I correct that if I want to have a release time of say 40 ms I would put 40 in place of .

For channel n+1. So channel 1 would be 0xB0,0x48, 40

This I have tried , it compiles but has no effect on fading of notes.
My lack of programming fails me.
Can you please spell it out for me how I set a fade in- out time for the notes.

This I have tried , it compiles but has no effect on fading of notes.

First step is to post your new code so we can see if it is the right place.

Then note the Manual page says:-

As of firmware v0.60 and above, the following controllers are also supported.

MIDI Controller number 73 (Attack) controls the WAV Trigger note-on attack time (0 to 2000 msecs).

MIDI Controller number 72 (Release) controls the WAV Trigger note-off release time (0 to 2000 msecs).

So what version of the firmware are you using?

And:-

Am I correct that if I want to have a release time of say 40 ms I would put 40 in place of .

that would be a no then.

As the third parameter of a CC message can only be a number from 0 to 127 and if the maximum release time is 2000ms then to get a 40ms time this would need a value of 2.54, which of course is impossible so use 3. Using a value of 40 will give you just a tad under 630mS. I would try a number of 127 here so it is noticeable.

What sort of Arduino are you using? Do you know this:-

It is very important to know that this is a 3.3V device, and its inputs – including triggers and serial RX – are not 5V tolerant!

Hi, The version of the firmware I am using is ; Tsunami Mono Firmware v1.08m
I am using an Arduino Uno sending serial Midi to the Tsunami opto-isolated MIDI input. Being
opto-isolated, it is fully compatible with regular 5V MIDI circuitry.
The sketch attached plays the notes on the four Banks ,but the release/ attack function has no effect.
Thank you for your help with my code? I attach a copy below.

#include 
void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);

}
int attack = 32; // =500ms
int release = 32; // =500ms
int CurrentMidiBank = 1;
int CurrentMidiChannel = 0;

void loop() {

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    CurrentMidiBank = bank;
    midiBank( CurrentMidiChannel, CurrentMidiBank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    // for (int note = 0x1E; note < 0x5A; note ++)
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( CurrentMidiChannel, note, 0x45);
      delay(1000);

      noteOff( CurrentMidiChannel, note, 0x00);
      delay(1000);
    }

    delay( 1500 );
  }
}

// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);

  Serial.write(release );
}

void midiattack ( byte channel, byte attack)
{
  midiMsg( (0xB0 | channel ), 0x49, attack);

  Serial.write( attack);
}
void midiBank( byte channel, byte bank )
{
  // Program Change, Bank select LSB = bank
  midiMsg( (0xB0 | channel ), 0x20, bank );

  // Program Change, program 0
  Serial.write( (0xC0 | channel) );
  Serial.write( bank );

}

// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte volume)
{
  midiMsg( (0x90 | channel), note, volume);
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte volume)
{
  midiMsg( (0x80 | channel), note, volume );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

Your sketch never calls midirelease() or midiattack()!

MarkT:
Your sketch never calls midirelease() or midiattack()!

Call them in the setup function if you are not going to change them.

Remove the lines

 Serial.write(release );
and
Serial.write( attack);

I have removed the lines , Serial.write(release ); and Serial.write( attack); as sugested from the sketch.

I have tried to call midirelease() / midiattack()! and also tried every thing else I can think of.

I cannot get this to work. I do not know what I am doing.

I attach a copy of my attempt below.

#include 
void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);

}
byte midirelease();
byte midiattack();
int CurrentMidiBank = 1;
int CurrentMidiChannel = 0;
int release = 18;  // =500ms
int attack = 18;   // =500ms


void loop() {

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    CurrentMidiBank = bank;
    midiBank( CurrentMidiChannel, CurrentMidiBank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    // for (int note = 0x1E; note < 0x5A; note ++)
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( CurrentMidiChannel, note, 0x45);
      delay(1000);

      noteOff( CurrentMidiChannel, note, 0x00);
      delay(1000);
    }

    delay( 1500 );
  }
}

// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);

}

void midiattack ( byte channel, byte attack)
{
  midiMsg( (0xB0 | channel ), 0x49, attack);
}
void midiBank( byte channel, byte bank )
{
  // Program Change, Bank select LSB = bank
  midiMsg( (0xB0 | channel ), 0x20, bank );

  // Program Change, program 0
  Serial.write( (0xC0 | channel) );
  Serial.write( bank );

}

// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte volume)
{
  midiMsg( (0x90 | channel), note, volume);
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte volume)
{
  midiMsg( (0x80 | channel), note, volume );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

Where in that code do you try and call the midirelease() & midiattack() functions?

I note you have defined a byte variable with the same name

byte midirelease();
byte midiattack();

Why are you doing that? It is not calling those functions.

Remove them and make your setup function:-

void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);
  midirelease(0,18);
   midiattack(0,18);
}

Also why do you have just #include at the start of your sketch?

Grumpy_Mike
Ok I have altered the code as you suggested .
This is still not working.
I have just #include at the start of your sketch because in cutting and pasting sketch I missed out <MIDI.h> .
I learn from my mistakes and I am still making them.
Altered code attached

#include  <MIDI.h>
void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);
  midirelease(0, 18);
  midiattack(0, 18);
}

int CurrentMidiBank = 1;
int CurrentMidiChannel = 0;
int release = 18;  // =500ms
int attack = 18;   // =500ms


void loop() {

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    CurrentMidiBank = bank;
    midiBank( CurrentMidiChannel, CurrentMidiBank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    // for (int note = 0x1E; note < 0x5A; note ++)
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( CurrentMidiChannel, note, 0x45);
      delay(1000);

      noteOff( CurrentMidiChannel, note, 0x00);
      delay(1000);
    }

    delay( 1500 );
  }
}

// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);

}

void midiattack ( byte channel, byte attack)
{
  midiMsg( (0xB0 | channel ), 0x49, attack);
}
void midiBank( byte channel, byte bank )
{
  // Program Change, Bank select LSB = bank
  midiMsg( (0xB0 | channel ), 0x20, bank );

  // Program Change, program 0
  Serial.write( (0xC0 | channel) );
  Serial.write( bank );

}

// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte volume)
{
  midiMsg( (0x90 | channel), note, volume);
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte volume)
{
  midiMsg( (0x80 | channel), note, volume );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

You need to issue the commands for the channel in question - so if you change CurrentMidiChannel to
something other than zero, your attack/release commands will need changing too.

You might want to select the bank before sending control change messages, they are likely to be
bank-specific, but read the docs for the MIDI device in question if possible.

MarkT:
You need to issue the commands for the channel in question - so if you change CurrentMidiChannel to
something other than zero, your attack/release commands will need changing too.

But the function says:-

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);
}

So the channel is passed as a parameter to the function.

I am getting confused, I do not understand the last two posts and there relevance as to getting my sketch working.

I do not understand the last two posts and there relevance as to getting my sketch working.

The relevance is that your code is rubbish, it seem that you don't even know how to call a function. This is one of the very basic fundamentals you need to do when you write a program.

As it stands your code is not sending the control data to your MIDI device. Which is why you are not hearing any effect. We are attempting to show you what corrections you need to make to your code in order for it to send this data.

Each MIDI channel you use requires this data to be sent to it, MarkT was pointing this out in reply #10. Then I was pointing out to Mark that the function you had written contains the channel data as one of the parameter to pass to it. So as long as you call this function for each channel you want to use along with the correct channel then all will be well.

Last post understood.
Ok, as you say my sketch is rubbish and my programming skills are also rubbish, this I know and this is why I am seeking advice.
I attach a modified sketch which does not work and is also properly rubbish, but is best I can think off.
What do I need to do?

#include 

int bank = 1;
int channel = 0;
int release = 18;
int attack = 18;




void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);
  midirelease(0, 18);    // =500ms
  midiattack(0, 18);
}


void loop()
{

  midiattack(channel, attack);
  midirelease( channel, release );

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    midiBank( channel, bank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    for (int note = 0x43; note < 0x4F; note ++)
    {

      noteOn( channel, note, 0x45, attack);

      delay(1000);

      noteOff( channel, note, 0x00, release);

      delay(1000);
    }

    delay( 1500 );
  }
}

// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);
  Serial.write( (0xC0 | channel) );
  Serial.write( release );
}

void midiattack ( byte channel, byte attack)
{
  midiMsg( (0xB0 | channel ), 0x49, attack);
  Serial.write( (0xC0 | channel) );
  Serial.write( attack );
}

void midiBank( byte channel, byte bank )
{
  // Program Change, Bank select LSB = bank
  midiMsg( (0xB0 | channel ), 0x20, bank );

  // Program Change, program 0
  Serial.write( (0xC0 | channel) );
  Serial.write( bank );

}

// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte velocity, byte attack)
{
  midiMsg( (0x90 | channel), note, velocity );
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte velocity, byte release)
{
  midiMsg( (0x90 | channel), note, velocity );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

What do I need to do?

Don't use so many spaces in between code lines, that won't stop it working but it will look nicer.
All the sound generators I have seen do not use banks 0 to 4 to generate different sound they use more.

I am not sure what you are trying to do because changing the bank will only make a difference to the timbre of the note when you change the "instrument" with a program change. You don't seem to be changing the instrument just the bank, that in itself will do nothing until you change the instrument. However, this code should sort out the attack and release parameters at least.

Not only read up how to write code but also what MIDI messages do, because unless you know what messages you want to send it is impossible to write code to send them.

int channel = 0;
int releasePram = 18;
int attack = 18;

void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);
  midirelease(channel, releasePram);    // =500ms
  midiattack(channel, attack);
}

void loop()
{
 // midiattack(channel, attack);   // only send it when you need to not hundreds of times a second
 // midirelease( channel, release ); // only send it when you need to not hundreds of times a second

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    midiBank( channel, bank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( channel, note, 0x45);
      delay(1000);
      noteOff( channel, note, 0x00);
      delay(1000);
    }
    delay( 1500 );
  }
}

void midirelease ( byte channel, byte pram)
{
  midiMsg(0xC0 | channel, 0x48, pram);
}

void midiattack ( byte channel, byte attack)
{
    midiMsg(0xC0 | channel, 0x49, attack);
}

void midiBank( byte channel, byte bank )
{
  // set MIDI bank LSB
  midiMsg(0xC0 | channel, 0x20, bank);
}

// plays a MIDI note. - restrict note and velocity to a maximum of 7F
// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte velocity)
{
  midiMsg( 0x90 | channel, note & 0x7F, velocity & 0x7F );
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte velocity)
{
  midiMsg(0x90 | channel, note & 0x7F, velocity & 0x7F );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

The reason for changing the bank is that when using MIDI, Tsunami maps MIDI Note number to track number, so MIDI Notes 1 – 128 map to Tracks 1 – 128. Similarly, a MIDI Bank feature shifts offsets the track number by 128, so MIDI Bank 1 maps MIDI Notes 1 – 128 to Tracks 129 – 256, and so on up to MIDI Bank 32. The MIDI Bank is incremented and decremented with the MIDI Program
Change message.
Sorry I should have made this clear in my first post.

Thank you so much for your code.
Unfortunately this at first did not work, but I figured out that the attack / release was set as 0xC0 Program Change message rather than 0xB0 Controller Change message.
This test sketch now works. Cheers.

Attached is working code.

#include <MIDI.h>
int bank = 1;
int channel = 0;
int release = 64; // =1000ms
int attack = 64;

void setup() {
  // Set MIDI baud rate:
  Serial.begin(31250);
  midirelease(channel, release);   
  midiattack(channel, attack);
}

void loop() {

  // Play notes in banks 0, 1, 2 and 3
  // (all on channel 0)
  //
  for ( int bank = 0; bank < 4; bank ++ )
  {
    midiBank( channel, bank );

    // play notes from G-3 (0x43) to G-4 (0x4F):
    // for (int note = 0x1E; note < 0x5A; note ++)
    for (int note = 0x43; note < 0x4F; note ++)
    {
      noteOn( channel, note, 0x127);
      delay(3000);

      noteOff( channel, note, 0x00);
      delay(3000);
    }
    delay( 1500 );
  }
}

// plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that
// data values are less than 127:

void midirelease ( byte channel, byte release)
{
  midiMsg( (0xB0 | channel ), 0x48, release);
}

void midiattack ( byte channel, byte attack)
{
  midiMsg( (0xB0 | channel ), 0x49, attack);
}

void midiBank( byte channel, byte bank )
{
  // Program Change, Bank select LSB = bank
  midiMsg( (0xC0 | channel ), 0x20, bank );
}

// Send a MIDI note-on message.
void noteOn(byte channel, byte note, byte velocity)
{
  midiMsg( (0x90 | channel), note, velocity);
}

// Send a MIDI note-off message.
void noteOff(byte channel, byte note, byte velocity)
{
  midiMsg( (0x90 | channel), note, velocity );
}

// Send a general MIDI message
//
void midiMsg(byte cmd, byte data1, byte data2 )
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}