Btw about the FileWatcher, when the csd changes I reparse it, and obviously we lose all the settings made before on the channels of CsoundUnity instances.
I think that even if now the inspector is keeping changes, the preset feature is totally needed!
CsoundUnity Package (UPM) development
Good to know. Iām just looking into the node component here. We need to access a ksmps sized buffer of audio from an audio rate channel. Our current getChannel() method returns a single k rate value. In C++ I can also access a-rate channel data, but as I said, itās in the form of an array. So we would need to update this method:
public MYFLT GetChannel(string channel)
{
return csound.GetChannel(channel);
}
which in turns means updating:
public MYFLT GetChannel(string channel)
{
return Csound6.NativeMethods.csoundGetControlChannel(csound, channel, IntPtr.Zero);
}
What about providing a wrapper to this function:
// PUBLIC int csoundGetChannelPtr (CSOUND *, MYFLT **p, const char *name, int type)
If we get a pointer we can access the full sample array? My only concern is that we may need to use the same ksmpsIndex. My idea is something as simple as this:
void OnAudioFilterRead(float[] data, int channels)
{
// MYFLT[] samples = csoundUnity.getChannel("bombSounds");
//and pass samples to this component's audiosource buffer...
}
Iām not sure about trying to access ksmpsIndex
from the main CsoundUnity object. I donāt even know if Unity will let us. An independent ksmps index might work, but Iāve no idea until I try it out.
[edit] So, the idea is that you generate your sounds in a master instance of CsoundUnity and send them to other objects using chnset:
instr 2
a1 oscili 1, 200
chnset a1 "oscil"
endin
And it will be picked up in the node object by simply calling csoundUnity.GetChannel()
. Once there, Unity will apply all the spatial attributes to it So we get sounds local to the object, that are generated elsewhere.
I pushed the FileWatcher update. It wasnāt easy as expected.
Tomorrow Iāll look into the methods to add, this seems a great design but Iām not sure I understand it totally. Maybe I need some sleep!
Iāll take a look at the file watcher stuff tomorrow. Thatās another big feature youāve just added. Youāre on a roll!
It seems I managed to
The problem is that I cannot filter the objects it shows by string, so thereās every object of type āDefaultAssetā in the window (called āObjectPickerā) that opens.
If we want to filter the files we have to open this window with EditorGUIUtility.ShowObjectPicker, but this can be called just from a custom button, thereās no way to intercept the click in the above circle button. We could fake the button to be like the inspector field, but itās a bit trivial!
The circle button can be drawn more or less like this:
var testRect = GUILayoutUtility.GetRect(0.0f, 20.0f, GUILayout.ExpandWidth(true));
GUI.Button(testRect, "testCircle", GUI.skin.GetStyle("IN ObjectField"));
Look at the difference between the inspector field where I can drag csd files (any other kind of file would null the csd reference of CsoundUnity) and the testCircle field:
I think that if thereās some more important feature to add this could be left for later!
Btw apart from the filter it seems to work. Iāll push the update to dev2 so that we can choose later!
Then Iāll look into the new methods to add.
I found this code in the example 9 of Csound6Net:
var bus = c.GetSoftwareBus();//Get bus and define the "amp" and "freq" channels of orc3
//Since orc3 instrument doesn't declare channels directly, define them here
var ampChannel = bus.AddControlChannel("amp", ChannelDirection.Input);
var freqChannel = bus.AddControlChannel("freq", ChannelDirection.Input);
//Prime with initial values accessing channel memory directly
//That is, it contains a call to csoundGetChannelPtr internally.
ampChannel.SetValueDirect(amps.Value); //Use
freqChannel.SetValueDirect(freqs.Value);
Very interesting! Maybe Iāll have a look at the GetSoftwareBus and SetValueDirect methods, and port them to CsoundUnity!!
Interesting, although Iām not sure how useful they are. I canāt think of many reasons where one would need to declare a channel outside of Csound? The setValueDirect() methods just duplicate:
csoundUnity.setChannel()
Or am I missing something?
No It should be a not threadsafe version to manage AudioChannels, as stated by the docs:
/// <summary>
/// Provides slightly quicker, but not threadsafe, updates to a channel's current value
/// as opposed to this class's threadsafe "Value" property.
/// Saves a hashtable lookup of the channel by name in csound's memory.
/// Uses csoundGetChannelPtr to acquire and keep the pointer to this channel's location
/// in csound's unmanaged memory.
/// Best used from the same thread such as when updating channels between calls to
/// PerformKsmps or PerformBuffer.
/// </summary>
/// <param name="value"></param>
public void SetValueDirect(double value)
{
var v = new double[1];
v[0] = value;
IntPtr pData = GetChannelPointer();//will throw exception if fails
Marshal.Copy(v, 0, pData, 1);
}
Value instead get/set an AudioChannel:
/// <summary>
/// Copies an audio channel's contents to/from a managed array for use in .net algorithms.
/// This property is the threadsafe way to move values between .net and csound's unmanaged memory.
/// </summary>
public override object Value
{
get
{
Double[] dest = new Double[Resize(m_csound.Ksmps)];//include nchnls/nchnlss_i? no, not an output channel: just a single ksmps-sized buffer
NativeMethods.csoundGetAudioChannel(m_csound.Engine, Name, m_buffer);
Marshal.Copy(m_buffer, dest, 0, dest.Length);
return (object)dest;
}
set
{
Double[] source = value as double[];
Resize(m_csound.Ksmps);
Marshal.Copy(source, 0, m_buffer, Math.Min(source.Length, m_bufsiz));
NativeMethods.csoundSetAudioChannel(m_csound.Engine, Name, m_buffer);
}
}
CsoundUnity.SetChannel is for a ControlChannel:
public void SetChannel(string channel, MYFLT value)
{
Csound6.NativeMethods.csoundSetControlChannel(csound, channel, value);
}
So maybe is what we need??
Iām going to implement this!
Btw have you checked the dev2 branch? Itās working good now!
But needs some tests!
Jut on the dev2 branch now. I never saw the getAudioChannel() method before. Nice one. thatāll do nicely. Let me know when itās pushed and I will test out my node interfaceā¦
Yes you can grab it now!
Ah, but this doesnāt have the GetAudioChannel or?
Not yet! Iāll add it in a couple of hours, this morning I was busy!
This version has the new way of setting the csd
Cool. Do both ways work then in this version> Dragging to the drag field AND selecting from the assets browser?
Yes exactly, hope they work in the same way
I quickly put together the Get/SetAudioChannel methods, hope they wonāt lead to lots of crashes
Iāll test them now!
If you push I can test here too
Should be there! always on dev2
Great. Just testing hereā¦
[edit] we have audio Now the problem is weaving the channel audio data into the audio source bufferā¦
Ha, no thatās not the tricky bit. This SHOULD work, but Iām wondering if not being synced to the ksmpsIndex of the master component is causing the audio problemsā¦
public void ProcessBlock(float[] samples, int numChannels)
{
MYFLT[] channelSamples = csoundUnity.GetAudioChannel(csoundChannels[0]);
//print(channelSamples.Length);
for (int i = 0; i < samples.Length; i += numChannels, ksmpsIndex++)
{
for (uint channel = 0; channel < numChannels; channel++)
{
if (ksmpsIndex >= csoundUnity.GetKsmps())
ksmpsIndex = 0;
samples[i + channel] = (float)channelSamples[ksmpsIndex];
}
}
}