Cabbage Logo
Back to Cabbage Site

CSoundUnity Beginner Questions

Thanks guys this works beautifully!

I’ve got lots to play around with now.

I noticed you added a “Trigger Note” button, is that what’s being called or just there for troubleshooting?

I just added that to test what the right score event should be before I brought it into unity :+1:

I just did a recording of the oscbnk_synth running on windows. Very interesting noise!!
Warning: keep your volume low! (headphones not recommended)

here it is (starts after 3s):

Btw: I found that other opcodes are not working: date, dates, sprintf
trying to record using this instr:

instr 1000
    prints "Starting recording\n"
    aL, aR monitor
    itim     date
    Stim     dates     itim
    Syear    strsub    Stim, 20, 24
    Smonth   strsub    Stim, 4, 7
    Sday     strsub    Stim, 8, 10
    iday     strtod    Sday
    Shor     strsub    Stim, 11, 13
    Smin     strsub    Stim, 14, 16
    Ssec     strsub    Stim, 17, 19
    Sfilname  sprintf  "%s_%s_%02d_%s_%s_%s.wav", Syear, Smonth, iday, Shor,Smin, Ssec
    fout Sfilname, 4 ,aL, aR

after removing those opcodes I can confirm recording an audio file through fout works on Windows!

We are kind of hijacking this thread, but try adding this to CsoundUnityBridge.cs:

        Environment.SetEnvironmentVariable("OPCODE6DIR64", csoundDir);
        Csound6.NativeMethods.csoundSetGlobalEnv("OPCODE6DIR64", csoundDir);
        Csound6.NativeMethods.csoundSetGlobalEnv("SFDIR", Application.streamingAssetsPath + "/CsoundFiles");
        Csound6.NativeMethods.csoundSetGlobalEnv("SSDIR", Application.streamingAssetsPath + "/CsoundFiles");
        Csound6.NativeMethods.csoundSetGlobalEnv("SADIR", Application.streamingAssetsPath + "/CsoundFiles");

I don’t think csoundSetGlobalEnv() is working correctly. After I made this change I was able to use the date opcodes. Still no luck with the exciter.dll though…

Added the SetEnvironmentVariable line but (on Windows 8.1, Unity 2019.3.9f1) date opcodes still not working here :face_with_raised_eyebrow:

That’s odd. I’ll check here again a little later and let you know…

No problem hijacking the thread, can’t say I’m quite able to follow though!

I don’t know if this is related to that lovely noise above, but I’m noticing different results from when I play the sound using CabbageLite and from within Unity (both with the same settings).

First is CabbageLite second is CSoundUnity.

Looking at the recorded waveform the Unity result is totally compressed.

That is odd. How are you recording the output?

Recorded with an output loopback into Audacity. But the clipping is definitely noticeable prior to recording.

EDIT: and I should mention that the that recording is with the Unity Audio Source ‘volume’ on the gameobject turned way down to 0.1

Let me fire up my Windows box and take a look…

Ok, wow, that’s embarrassing! I failed to see that Iain was already scaling the MIDI velocity between 0 and 1. And here was I suggesting a moderate MIDI velocity of 80 :laughing: This works a whole lot better:

csoundUnity.SendScoreEvent("i2 0 3 60 .7");

No more distortion or samples out of range.

ehm… :thinking:
I still have the infinite volume output (and the noise)… could it be something that has not initialized?
(on macOS 10.13.3)

I’m not getting any noise. In fact, I was never getting any noise? :thinking: But you’re probably correct in that it sounds like something is not initialised correctly…

Thanks Rory that was it, sounds great for me now. yeah velocity scaling 0-1 actually makes a lot more sense to me, I’ll keep an eye out for how the instruments have been set though.

Hey @Alex_Emile, how is it going? You still making progress? Let us know if you hit any roadblocks :wink:

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:


form caption("Read soundfile"), size(300, 200)

-n -d -m0d

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





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"));

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

    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";
            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);

Later I’ll check the csd you posted to see if I can make it work on Unity.
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

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}");