Cabbage Logo
Back to Cabbage Site

CSoundUnity Beginner Questions

Hi Rory, thanks for checking in. I’ve not had as much time to work on it as I’d have liked to, but have been slowly making my way through the documentation you sent me, and have successfully got some basic VR tests using the OscBankSynth, which at least comforts me in that this method is definitely the one I’ll be going forward with.

As for roadblocks, I’ve come across a few. Mainly in trying to set up some other example .csd’s to work with, in particular the CZSynth which I can’t seem to get a trigger on. I’ve edited the code using the OscBankSynth we worked on as a reference, but I must be missing something obvious.

Here’s my edited version: CZSynth.csd (22.6 KB)
The changes are on lines:

  • 192 (adding the test trigger button UI)
  • 202 (from: -dm0 -n -+rtmidi=null -M0 to: -n -d)
  • 236 (adding the triggerNote button event)
  • 418 (from: inum notnum to: inum = p4) Not sure why exactly but I just copied the edit we made on the other synth
  • 533 (to add: i 1000 0 z)
  • 534 (to add: f0 z)

This seems to compile but there are some warnings in the log so hopefully it’s because of something obvious in my edits.

Further questions:

  • What would be the best way to edit synth parameters from within Unity (preferably whilst in playmode) and have the changes saved as a preset? I managed to get a Save button that saves a snapshot working from within Cabbage, would this kind of thing work in Unity or is there a better way?
  • I really like the idea of the Patcher window in Cabbage to route an instrument to an effect, would there be any way to use a similar system from within Unity? or even better as a UnityGraph that links up .csd nodes from the editor… That would be awesome.

I did also try getting the LoscilFilePlayer example to work as a sampler, but Unity doesn’t pick up on the “Add file” prompt. I’m thinking I would need to change it from a button to a “drag here” area? That or the CSound instrument loads up the samples automatically seeing as at this point the sample can be pre-defined.

Just a quick reply with a sample for file loading:

csd:

<Cabbage>
form caption("Read soundfile"), size(300, 200)

</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -m0d
</CsOptions>
<CsInstruments>

sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1.0


instr 1

prints p4 

;if you have mp3s use mp3in
;ibufsize = 64
;ar1, ar2 mp3in p4, 0, 0, 0, ibufsize
;for pcm files use diskin2
a1, a2 diskin2 p4, 1, 0, 1
outs a1, a2

endin

</CsInstruments>
<CsScore>

</CsScore>
</CsoundSynthesizer>

C#:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class ReadFileController : MonoBehaviour
{
    public string[] AudioFilesNames;

    void Awake()
    {
        //assign member variable
        csoundUnity = GetComponent<CsoundUnity>();
    }

    private CsoundUnity csoundUnity;
    private Dictionary<int, string> _audioFilePaths;

    // Use this for initialization
    void Start()
    {
        _audioFilePaths = new Dictionary<int, string>();
        var count = 0;
        foreach (var fileName in AudioFilesNames)
        {

            var path = Path.Combine(Application.streamingAssetsPath, fileName);
            Debug.Log($"Checking path: {path} \nFile Exists? " + (File.Exists(path) ? "true" : "false"));

#if UNITY_EDITOR_OSX
            // path = "file://" + path;
#endif
            _audioFilePaths.Add(count, path);
            count++;
        }
        //comment this if you don't want autoplay of the first sample
        StartPlaying(0);
    }

    public void StartPlaying(int fileIndex)
    {
        SendScoreEvent(1, fileIndex, true);
    }
    public void StopPlaying(int fileIndex)
    {
        SendScoreEvent(1, fileIndex, false);
    }

    //send score works also with instruments with string names, 
    //but sending stop with i-instrName doesn't work
    //so use ints for now
    //also, to stop the instrument, this should be started with infinite duration
    void SendScoreEvent(int instrNum, int fileIndex, bool isStart)
    {
        var score = "i ";
        if (!isStart)
        {
            score += "-" + instrNum + " 0 0";
        }
        else
        {
            var path = _audioFilePaths[fileIndex];
            Debug.Log($"Checking path: {path} \nFile Exists? " + (File.Exists(path) ? "true" : "false"));
            //sending score with full path enclosed in escape chars
            score += (instrNum + " 0 -1" + " \"" + path + "\"");
        }
        Debug.Log("sending score: " + score);
        csoundUnity.SendScoreEvent(score);
    }
}

Later I’ll check the csd you posted to see if I can make it work on Unity.
Cheers!
EDIT: (the dictionary seems pretty useless you could pass directly the AudioFileNames by index)
Here I’m passing the file path as p4, ie the fourth element of the score, so the score becomes something like this:

i 1 0 -1 "/pathToProject/Assets/StreamingAssets/piano2.wav"

instrument 1 (p1, instr number) 0 (p2, start time, immediate) -1 (p3, duration of instr performance, negative if you want it to last forever until you stop it) “path” (p4)

I wouldn’t use a dictionary either but I think @giovannibedetti was just using it for testing purposes. You should probably just load all your samples explicitly rather than trying to implement any kind of drag and drop or GUI loading.

Regarding CZSynth. Here’s version with very little modifications.
CZSynth.csd (23.1 KB)
I just adding a new instrument:

instr 5
    gkcps = p4
    gkVel init p5
    event_i "i", 3, 0, p3, cpsmidinn(p4), p4
endin  

And kept everything else the exact same. I can then call:

csoundUnity.SendScoreEvent("i5 0 3 60 1");

And it plays.

That preset save feature in Cabbage is implemented in the plugin SDK, so it won’t work here. What I would do is write the current channel values to a file. Then when needed, read the file and update the channels. The easiest way would be to expose some of the Csound API channel methods. I’ll ask Giovanni if he can take a look :wink: Leave it with us.

Thanks for the tips @giovannibedetti, I’ll test the sampler today.

@rorywalsh, I managed to get that playing but it comes through really distorted, similar sound to when we’d sent the wrong velocity. Though this time it doesn’t seem to be clipping, does it sound normal on your end? I’m using exactly the file you sent across.

EDIT: Comparison, Unity first, Cabbage second (Warning: it’s a nasty sound)

public string midiNote = "61";
public string velocity = "0.7";
csu.SendScoreEvent("i5 0 3 " + midiNote + velocity);

I see a typo in the score string! you’re summing up the midi note and velocity.
change the third line to:

csu.SendScoreEvent("i5 0 3 " + midiNote + " "+ velocity);

btw I suggest using C# string interpolation for clarity

csu.SendScoreEvent($"i5 0 3 {midiNote} {velocity}");

Oops, yes that’s right, though I was testing it also as simple “i5 0 3 60 1” which got the same sound result.

You’re right about the string interpolation, that looks much cleaner.

so the problem persists?

Yeah same issue still.

Tried the csd, I can confirm your result: what I hear is like an aliasing, very strange!
I can also say it could be a sample rate problem: on macOS the note I hear is lower than yours, about a semitone lower. That is something I noticed some time ago. I think we should look again into the sample rate settings and find what’s wrong. Let’s hope @rorywalsh has some ideas…

Hi guys, sorry for the delay in getting back to you. I do hear an issue. Sorry, I never noticed it yesterdasy as the sound was coming from my Occulus headset, that was positioned not on my head, but on my desk! I think the problem is with the widgets Iain is using, namely the combobox boxes, which aren’t supported. I think what we are hearing is Waveform - Noise setting. Let me swap out the combobox boxes for sliders and see how it is…

[edit] CZSynth.csd (23.1 KB) is a little better but still not picking up the complete default values from Iain’s, but a step in the right direction… I’m going to sort the combobox issue now, so that by default, CsoundUnity will convert them to sliders…

See next post…

I’ve just pushed support for comboboxes to the develop branch. The CZSynth example sounds much better now I think.

Hi @rorywalsh, that seems to have fixed it. With a few adjustments they sound identical which is great.

It seems though that when I go to change params on the synth in playmode and hop to a different GameObject some parameters go back to default whilst others don’t (visually everything looks like it goes back to default but not sonically). This is the same with the OscBankSynth btw.

Oh, I’ve just seen @giovannibedetti’s post from yesterday CsoundUnity Package (UPM) development
If I’m understanding correctly that would solve the issue I’m referring to?

I think this is true. As a workaround you can save a preset of the CsoundUnity inspector, or use CopyComponent, and then reapply when coming back to the same GameObject.

For now it does not produce sound at all so it brings more problem instead of solving them. But yes the aim is changing how CsoundUnity stores things in the editor.
But I have just finished developing (with a complete rewrite of the Editor script), so now it’s just a matter of finding what’s wrong with it :sweat_smile:

I didn’t even know one could do this :see_no_evil: Nice one. It’s not a bad stop-gap solution.

Yes this is a trick you learn when you modify lots of things around while in play mode, and then you stop and lose everything :face_with_symbols_over_mouth:

Oh wow. My life just got a lot less frustrating!!

1 Like

First thing I tried yesterday! Doesn’t seem to pick up on the changes, visual or sonic though.

It’s because it reparses the csd everytime you select the GameObject in the inspector, calling OnEnable of the Editor script. This is one of the reasons of the rewrite :sweat_smile:
So for now note the values you change by hand :roll_eyes:

1 Like

Id love to participate <3 hit me up! @Alex_Emile :slight_smile: www.axiom-crux.net you can use my contact form on my site :slight_smile:

1 Like