Cabbage Logo
Back to Cabbage Site

CsoundUnity on MacOS

Ok. That’s good to know. Worst case scenario we can write a post processor for OSX that will put the framework in the right place. But it looks promising.

I guess we also have to bundle the .csd files into a resources folder for the standalone builds right?

Exactly!

For sure we have to avoid to have them compiled in the binary. So the choices are again the StreamingAssets and Resources folders. I’ll look into AssetBundles and Addressables, but we cannot force the user to use them.
Also the user must be aware of the right location where to put his csd files, so maybe some Editor script that warns him if they’re put in the wrong location can be an option?

Had a look at the player log, after copying the CsoundLibr64.framework inside the .app built by Unity (you can find log at Library/Logs/Csound/CsoundUnityPackage/Player.Log)

Fallback handler could not load library [removed path]Test.app/Contents/Frameworks/MonoEmbedRuntime/osx/libCsoundLib64.framework/CsoundLib64

DllNotFoundException: CsoundLib64.framework/CsoundLib64
  at (wrapper managed-to-native) csoundcsharp.Csound6+NativeMethods.csoundSetGlobalEnv(string,string)
  at CsoundUnityBridge..ctor (System.String csoundDir, System.String csdFile) [0x0001c] in <0519b2c4b8f74c5ab9bba966b994a8c1>:0 
  at CsoundUnity.Awake () [0x0006a] in <0519b2c4b8f74c5ab9bba966b994a8c1>:0 

It seems the fallback handler is looking for a library called libCsoundLib64.framework/CsoundLib64, I’ll rename it and see what happens!

There is another way :thinking:

We add csoundCompileCsdText() and simply pass the .csd file as a string from a C# script when we compile Csound. It means users will have to do some extra copying of text between whatever editor they use and Unity. it’s not the worst scenario, but it would be nice to be able to edit in place. How about we create a script that will convert any .csd file to a txt file that could be loaded as a TextAsset? Or? I’m just thinking it would be nice to be able to open your favourite Csound editor and load and edit your game instruments directly, without having to then copy and paste them back into a c# script. Any ideas how we can do it? I think csoundCompileCsdText is definitely part of the answer.

Another thing that is going to cause issues are loading audio samples. Right now they are put into streaming assets because Csound needs to load them from disk. AFAIK, when Unity creates its standalone all audio files they all get written into the game binary. This isn’t going to work at all. If there any way we can extract them from the binary and place them somewhere? I can see people having an issue with this one as it means anyone playing their games have access to all their audio assets. That’s not good.

I think I might have a workable solution for the audio samples. We simply grab the sample data at runtime using getData(), and then pass the data to function tables when we first instantiate our instruments. We would need to write a simple sendToFunctionTable(data, fn) method so that users can manage it themselves, but I think it should work Ok.

Anyhow, I think the first thing to try to sort is the issue of it not working in OSX standalones…

I like the fact that I can modify the csd in my fav Csound editor (ie Cabbage :wink:) and Unity is aware of the changes, and also updates the channel controllers accordingly on the inspector.
So maybe it’s a matter of copying the csd files as text assets in a special position just when building (Resources folder should leave its content untouched), and load them as text assets instead of csd (if it’s really needed) when in build. They can just stay there also when developing in editor.

This page about Unity special folders is very helpful.
One of the main reasons I prefer Resources folder is this line:

You can have multiple Resources folders placed anywhere inside the Assets folder.

So we can have our CsoundUnity folder inside Assets, a folder for each example scene, and a Resources folder for every scene from where we can load related csd and audio files.
Seems very clean to me.
I should ask my boss what he thinks about it :rofl:
I’m not sure it will work on android, and maybe we will have to copy the files in persistentDataPath when the app is started for the first time.
Let me do some tests!

All jokes aside, it would actually be interesting to get his thoughts!

@giovannibedetti Have you any idea why spin is getting cleared each time we change a slider in the editor when performing?

EDIT:
Yes It’s these lines:

EditorGUI.BeginChangeCheck();
EditorGUILayout.Toggle("Process Clip Audio", m_processAudio.boolValue);
if (EditorGUI.EndChangeCheck())
{
   csoundUnity.ClearSpin();
   csoundUnity.processClipAudio = !m_processAudio.boolValue;
}

they check for a change in the editor, if a change happens to the processClipAudio toggle the spin is cleared.
But maybe they are called also if you move a slider.
I’ll add some check to avoid that!

I checked this and the clear spin is not called. It seems to be ok :thinking:

Btw I tried to understand why opcodes64 aren’t available. If I debug Directory.Exists from a folder in the package this never exists. :thinking:
We also have to have a look at the Awake method of CsoundUnity, there’s some path to fix

We need to set opcodedir64 variable… not at PC now but can check later if we do this…

Ok I fixed the Opcode folder! Now the plugins are loaded on macOS!!!
(it was a wrong path)

Great, thanks. I imagine the dir is wrong on Windows too now that we move the location of Csound around:

I am on my Mac now but I can take a look later if you’re not on Windows. :+1:

Should be ok 'cause the dlls for Win are all in the same place, I fixed the dataPath in CsoundUnity:

string dataPath = Path.GetFullPath(Path.Combine("Packages", packageName, "Runtime"));
    
if (string.IsNullOrWhiteSpace(csoundFile)) return;

csoundFilePath = Application.streamingAssetsPath + "/CsoundFiles/" + csoundFile;

#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
    dataPath = Path.Combine(dataPath, "Win64"; // Csound plugin libraries in Windows Editor

EDIT: I thought I had fixed, I see now the missing parenthesis :sweat_smile:

The simple test is to check the instrument I posted to @Alex_Emile yesterday. Uncomment the exciter code. If OPCODE6DIR64 is correct then it should find the exciter opcode. I can try myself after lunch. I have to go back to Windows then anyway…

On macOS it works!
I have an hard disk with Windows, so I can try it later.
When you finish lunch I have two questions:

  • why midi is not working? I see the midi channels logged on play in Unity. Maybe the ports settings are missing? Is this difficult to make it work? Sorry I have no idea on this :blush:
  • how to save the settings made on a channel via Unity editor? I think it could be useful to have some button like “Save Settings” that saves defaults values to the Cabbage section of the csd. Do you have some suggestion other than rewrite the whole section?

I can confirm that OPCODE6DIR64 is being set correctly. I just can’t tell you why it doesn’t load the exciter opcode. I have to see if it actually loads any of the plugin opcode libraries.

I never tried using an external MIDI controller with Unity and Csound. If you want to try it you have to set the correct MIDI hardware flag in your CsOptions. I have on the other hand read MIDI files with CsoundUnity. That works fine but reading MIDI files in Csound is a straight start to finish job. There is no way of modifying the tempo, volume etc.

I would just add a ‘preset’ button that writes the channel data to file. Csound has a few opcodes that can be used to read and write data. I also wrote some opcode to do just this some time back, although it was mostly a proof of concept:

https://rorywalsh.github.io/csoundPluginOpcodes/#/channelStateRecall
https://rorywalsh.github.io/csoundPluginOpcodes/#/channelStateSave

Either way, it’s not a big job. The question is whether it should be done automatically by CsoundUnity or the end user? I’m a big fan of lesser moving parts, but this might be a nice feature to have…

I can confirm that other plugins opcode libraries do work fine. Just not exciter :thinking:

I’m testing this on Windows too. The plugin is not loaded but the path is correct.

Btw I have a strange behaviour with the oscbnk_synth.csd: sound (…well it’s noise), on first note then silence. It seems like something is not loaded properly. i get this strange log with infinite volume:

Ok I’ll try simulating a midi device :grin:

Me too. It’s a nice to have, but it’s just a matter of saving the values in the csd. So not on the top of the todo list for now.

Oh no, I wouldn’t recommend that approach. Too risky. Better to say them in an eternal file and then load them with Csound.

That’s odd. Although I don’t think it’s related, I did notice that zerodbfs is no longer being using the ProcessBlock() method. It should definitely be in there. All samples to and from Csound should be scaled by this. It should probably be something like:

public void ProcessBlock(float[] samples, int numChannels)
{
    if (compiledOk)
    {
        for (int i = 0; i < samples.Length; i += numChannels, ksmpsIndex++)
        {
            for (uint channel = 0; channel < numChannels; channel++)
            {
                if (mute == true)
                    samples[i + channel] = 0.0f;
                else
                {
                    if ((ksmpsIndex >= ksmps) && (ksmps > 0))
                    {
                        PerformKsmps();
                        ksmpsIndex = 0;
                    }

                    if (processClipAudio)
                    {
                        SetInputSample((int)ksmpsIndex, (int)channel, samples[i + channel] * zerdbfs);
                    }
                    samples[i + channel] = (float)GetOutputSample((int)ksmpsIndex, (int)channel) / zerdbfs;
                }
            }
        }
    }
}

In most cases this is redundant because 0dbfs will be 1, but if some unfortunate user doesn’t set 0dbfs to 1 they will blow the ears off themselves. By default, 0dbfs in Csound is 2^16/2.