Cabbage Logo
Back to Cabbage Site

How can I use the Serial Opcode to trigger a sound from an Arduino?

Edit
I was originally trying to do something else, but when I tried to simplify my problem I ended up trying to play a sound in cabbage that was triggered by a button press from an Arduino device. Hence I had to update the title of this topic.

I have two small Csound programs that run fine independently of one another, but not together.
The first Program reads a value using the serial opcode, I have it hooked up to an Arduino and when I press a button it prints 1, and when I release it, it prints 0. The code looks like this

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort

printks("\nValue is %d", 0.001, kType)

The second allows me to get input from my microphone and plays it back to me, it records when I press the button and stops recoding for the second press. The Sampler Opcode works fine, and the rest of the code looks like this.

kTrig = chnget:k("record")    
kSpeed = chnget:k("speed") 
kSampleLength = chnget:k("sampleLength")
kSpeed = 1

a1, a2  in

aOutput Sampler (a1 + a2), kTrig, kSpeed, kSampleLength, 1

aOutput *= chnget:k("gain")

outs aOutput, aOutput

The Problem is when I attempt to combine them I get crashing, and Csound doesn’t read anything from my mic. If I look at the settings in cabbage, I can see input being received from my microphone before I run anything with the serial opcode but after I run it the input stops receiving anything until I plug in and out my Arduino.

The Combined Code Looks like this

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort


printks("\nValue is %d", 0.001, kType)


kTrig = kType //chnget:k("record")    
kSpeed = chnget:k("speed") 
kSampleLength = chnget:k("sampleLength")
kSpeed = 1

a1, a2  in

aOutput Sampler (a1 + a2), kTrig, kSpeed, kSampleLength, 1

aOutput *= chnget:k("gain")

outs aOutput, aOutput

You see it’s the input that is causing the problem? Can you do:

a1, a2 init 0

Jut to see if it behaves the same. Of course you’ll get no input, but let’s see if it still crashes…

I think I may have narrowed it down to a the serialRead.
I have replaced the output with a simple oscillator.

in my Arduino code, I am only writing once, when I press the button. So I think what is happening is the Csound code is looping back around to serialRead and waiting for more input.

The problem is if I constantly write values to the stream there is a huge delay of up to 10 seconds before Csound picks up the new value, I think it is caused by a big backlog of data in the stream.

So I am a bit stumped on how to find a way around this, The way I would think is to check in Csound if there is anything in the stream, but I am unsure of how to do that there doesn’t seem to be an opcode to check id the serial port has no data in it.

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort

//49 is the ascii code for "1"
if(kType == 49) then
	kEnv madsr .1, .2, .6, .4
    aOut vco2 0.5, 440
    outs aOut*kEnv, aOut*kEnv
endif

I don’t think the serialRead opcode could be blocking. That would be crazy.

In the simplest terms, what I am trying to achieve at the moment is to play a sound when I have the button on the Arduino pressed, and stop it when it is released.

Try:

//49 is the ascii code for "1"
if(kType == 49) then
    aOut vco2 0.5, 440
    outs aOut*.5, aOut*.5
endif

Same thing seems to happen, Every time I press the Button I get a little blip of a sound that lasts less than a tenth of a second.

Sounds like your button is sending a single 1 followed by a zero very shortly afterwards. Just do this and see what you get:

printk2 kType

I imagine you get something like:

1
0

Can you show your arduino code?

Yes Arduino code looks like this

int button = 4;

int lastState;
int currentState;

void setup() {
  // enable serial communication
  Serial.begin(9600);
  pinMode(4, INPUT);

}

void loop() {
      currentState = digitalRead(4);
      
      if(currentState != lastState){
        Serial.write("1");
      }
       lastState = currentState;
}

the monitor in the Arduino prints a 1 every time i press the button

And what happens when you do this? What does Csound show?

It seems to Only Print the first Time I press The Button?

And if you take out everything apart from the Arduino code, does it still only print once? I’m just trying to figure out if there is something messing it up…

But hold on, your Arduino code will always write 1? You only ever write one? Should you not reset it at some point back to 0?

Yes actually I probably should change it back, Ill do that now.

If I change all the code to this

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort

printks("\nValue is %d", 0.001, kType)

It prints every time i press the button.

Yes because that code prints all the time. printk2 only prints when the value changes. Also, Why are you sending a char? Why not just do:

Serial.write(1);

Does that not work?

When I just send it a 1, it comes up as that little square character in the serial monitor, I think serial.write takes a char.

I have updated the Arduino code to this

  currentState = digitalRead(4);
  
  if(currentState != lastState)
  {
    if(currentState == 1)
    {
      Serial.write("1");
    }
    else
    {
      Serial.write("0");
    }
  }

and now this code

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort

printk2 kType

Prints 49 on button press and 48 on release.

So you’re good to go :+1: or?

Nope, it still just plays for a split second. I am convinced that the serial read is blocking it.

My Most recent attempt plays an awful sound when I release the button that doesn’t stop until I unplug the Arduino of force close cabbage.

Arduino Code

int button = 4;

int lastState;
int currentState;

void setup() {
  // enable serial communication
  Serial.begin(9600);

  pinMode(4, INPUT);

}

void loop() {
  currentState = digitalRead(4);

  if(currentState != lastState)
  {
    if(currentState == 1)
    {
      Serial.write("1");
    }
    else
    {
      Serial.write("0");
    }
  }
  lastState = currentState;
}

Csound Code

<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 500 ; the default krate can be too fast for the arduino to handle
0dbfs = 1

instr 1

//Start Serial Communication
iSerialPort	serialBegin	"/COM3", 9600

//Read the values into a slower k-rate variable
kType serialRead iSerialPort

printk2 kType

kAmp init 0;

if(kType == 49) then
    kAmp = 0.5
elseif(kType == 48) then
    kAmp = 0
endif

    aOut vco2 0.5, 440
    
    outs aOut * kAmp, aOut * kAmp

endin
</CsInstruments>
<CsScore>
i 1 0 z
e
</CsScore>
</CsoundSynthesizer>