/** * Example 8 - More efficient Channel Communications (in a single threaded host) * * This example builds on Example 7 by replacing the calls to SetChannel * with using GetChannelPtr. In the Csound API, using SetChannel and GetChannel * is great for quick work, but ultimately it is slower than pre-fetching the * actual channel pointer. This is because Set/GetChannel operates by doing a * lookup of the Channel Pointer, then setting or getting the value. This * happens on each call. The alternative is to use GetChannelPtr, which fetches * the Channel Pointer and lets you directly set and get the value on the pointer. * The approach shown here is only safe if you remain in a single thread * such as managing channel values in between calls to PerformKsmps. * * The thread-safe method shown in Example6 is preferred when using events in * a multithreaded environment such as was hinted at in Example4. * You can use the Channel Pointer technique when using threads but you must use * a channel lock to take care in not to creating a race condition while using * memory shared between host and csound itself thereby causing potential glitches * in your music. Further, since you write directly into unmanaged memory when * using this technique, getting even one byte of data wrong can crash your program. * * Like other managed hosts (like python), C# provides mechanisms that attempt * to contain your ability to do this. * The C# version supplies Get/SetValueDirect methods for channels which use * the channel objects declared name and direction and limits memory access to the * actual size defined for the channel's type. * The call to the memory pointer (GetChannelPtr) is internal and the returned pointer * is used whenever GetValueDirect or SetValueDirect is called thereby preserving * the speed advantage mentioned in the python example. * * Managing thread locks in host code is beyond the scope of this tutorial. * Use the method shown in Example6 when using more than one thread. * * The code below shows how to make indirect use of the .net Csound6Channel * object's GetChannelPtr function to touch channel memory directly. * */ public void Example8() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); c.SetOption("-m7"); c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n"); //Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amps = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freqs = new RandomLine(400, 80); // create RandomLine for use with Frequency 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 ampChannel.SetValueDirect(amps.Value); //Use freqChannel.SetValueDirect(freqs.Value); while (!c.PerformKsmps()) { //continue to update memory for the two channels directly ampChannel.SetValueDirect(amps.Value); freqChannel.SetValueDirect(freqs.Value); } c.Stop(); } }
/* Example 7 - Communicating continuous values with Csound's Channel System * * This example introduces using Csound's Channel System to communicate * continuous control data (k-rate) from a host program to Csound. The * first thing to note is the RandomLine class. It takes in a base value * and a range in which to vary randomly. The reset functions calculates * a new random target value (this.End), a random duration in which to * run (this.Dur, expressed as # of audio blocks to last in duration), and * calculates the increment value to apply to the current value per audio-block. * When the target is met, the Randomline will reset itself to a new target * value and duration. * * In this example, we use two RandomLine objects, one for amplitude and * another for frequency. We start a Csound instrument instance that reads * from two channels using the chnget opcode. In turn, we update the values * to the channel from the host program. In this case, because we want to * keep our values generating in sync with the audio engine, we use a * while-loop instead of a CsoundPerformanceThread. To update the channel, * we call the SoftwareBus's channel indexer methods with new values. * * Note: The Value property on the RandomLine objects not only gets * us the current value, but also advances the internal state by the increment * and by decrementing the duration. * * In the C# object wrappers, channels are objects which are most easily used * via a software bus object as this implemetation demonstrates. */ public void Example7() { using (var c = new Csound6NetRealtime()) { c.SetOption("-odac"); // Set option for Csound c.SetOption("-m7"); // Set option for Csound c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n");//Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amp = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freq = new RandomLine(400, 80); // create RandomLine for use with Frequency var bus = c.GetSoftwareBus(); //Channels can be created explicitly: bus.AddControlChannel("amp", ChannelDirection.Input); bus["amp"] = amp.Value; //Add an initial value: Value property changes after each use //Or channels can be created implicitly just by using it: //The bus's channels can be accessed by name like a dictionary. //If they don't yet exist, they will be defined (input/output as default) bus["freq"] = freq.Value;//Create and provide and initial value in one call //Now we have our channels: update them with new RandomLine values after each ksmps cycle: while (!c.PerformKsmps()) { bus["amp"] = amp.Value; bus["freq"] = freq.Value; } c.Stop(); } }
/** * Example 8 - More efficient Channel Communications (in a single threaded host) * * This example builds on Example 7 by replacing the calls to SetChannel * with using GetChannelPtr. In the Csound API, using SetChannel and GetChannel * is great for quick work, but ultimately it is slower than pre-fetching the * actual channel pointer. This is because Set/GetChannel operates by doing a * lookup of the Channel Pointer, then setting or getting the value. This * happens on each call. The alternative is to use GetChannelPtr, which fetches * the Channel Pointer and lets you directly set and get the value on the pointer. * The approach shown here is only safe if you remain in a single thread * such as managing channel values in between calls to PerformKsmps. * * The thread-safe method shown in Example6 is preferred when using events in * a multithreaded environment such as was hinted at in Example4. * You can use the Channel Pointer technique when using threads but you must use * a channel lock to take care in not to creating a race condition while using * memory shared between host and csound itself thereby causing potential glitches * in your music. Further, since you write directly into unmanaged memory when * using this technique, getting even one byte of data wrong can crash your program. * * Like other managed hosts (like python), C# provides mechanisms that attempt * to contain your ability to do this. * The C# version supplies Get/SetValueDirect methods for channels which use * the channel objects declared name and direction and limits memory access to the * actual size defined for the channel's type. * The call to the memory pointer (GetChannelPtr) is internal and the returned pointer * is used whenever GetValueDirect or SetValueDirect is called thereby preserving * the speed advantage mentioned in the python example. * * Managing thread locks in host code is beyond the scope of this tutorial. * Use the method shown in Example6 when using more than one thread. * * The code below shows how to make indirect use of the .net Csound6Channel * object's GetChannelPtr function to touch channel memory directly. * */ public void Example8() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); c.SetOption("-m7"); c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n");//Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amps = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freqs = new RandomLine(400, 80); // create RandomLine for use with Frequency 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 ampChannel.SetValueDirect(amps.Value); //Use freqChannel.SetValueDirect(freqs.Value); while (!c.PerformKsmps()) { //continue to update memory for the two channels directly ampChannel.SetValueDirect(amps.Value); freqChannel.SetValueDirect(freqs.Value); } c.Stop(); } }
/* Example 7 - Communicating continuous values with Csound's Channel System * * This example introduces using Csound's Channel System to communicate * continuous control data (k-rate) from a host program to Csound. The * first thing to note is the RandomLine class. It takes in a base value * and a range in which to vary randomly. The reset functions calculates * a new random target value (self.end), a random duration in which to * run (self.dur, expressed as # of audio blocks to last in duration), and * calculates the increment value to apply to the current value per audio-block. * When the target is met, the Randomline will reset itself to a new target * value and duration. * * In this example, we use two RandomLine objects, one for amplitude and * another for frequency. We start a Csound instrument instance that reads * from two channels using the chnget opcode. In turn, we update the values * to the channel from the host program. In this case, because we want to * keep our values generating in sync with the audio engine, we use a * while-loop instead of a CsoundPerformanceThread. To update the channel, * we call the SetChannel method on the Csound object, passing a channel name * and value. Note: The getValue method on the RandomLine not only gets * us the current value, but also advances the internal state by the increment * and by decrementing the duration. * * In the C# object wrappers, channels are objects which are most easily used * via a software bus object as this implemetation demonstrates. */ public void Example7() { using (var c = new Csound6NetRealtime()) { c.SetOption("-odac"); // Set option for Csound c.SetOption("-m7"); // Set option for Csound c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n");//Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amp = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freq = new RandomLine(400, 80); // create RandomLine for use with Frequency var bus = c.GetSoftwareBus(); //The bus's channels can be accessed by name like a dictionary. //If they don't yet exist, they will be defined (input/output as default) bus["amp"] = amp.Value; //Create and provide and initial value for an amplitude channel bus["freq"] = freq.Value;//Create and provide and initial value for a frequency channel while (!c.PerformKsmps()) { bus["amp"] = amp.Value; bus["freq"] = freq.Value; } c.Stop(); } }
/* Example 7 - Communicating continuous values with Csound's Channel System * * This example introduces using Csound's Channel System to communicate * continuous control data (k-rate) from a host program to Csound. The * first thing to note is the RandomLine class. It takes in a base value * and a range in which to vary randomly. The reset functions calculates * a new random target value (self.end), a random duration in which to * run (self.dur, expressed as # of audio blocks to last in duration), and * calculates the increment value to apply to the current value per audio-block. * When the target is met, the Randomline will reset itself to a new target * value and duration. * * In this example, we use two RandomLine objects, one for amplitude and * another for frequency. We start a Csound instrument instance that reads * from two channels using the chnget opcode. In turn, we update the values * to the channel from the host program. In this case, because we want to * keep our values generating in sync with the audio engine, we use a * while-loop instead of a CsoundPerformanceThread. To update the channel, * we call the SetChannel method on the Csound object, passing a channel name * and value. Note: The getValue method on the RandomLine not only gets * us the current value, but also advances the internal state by the increment * and by decrementing the duration. * * In the C# object wrappers, channels are objects which are most easily used * via a software bus object as this implemetation demonstrates. */ public void Example7() { using (var c = new Csound6NetRealtime()) { c.SetOption("-odac"); // Set option for Csound c.SetOption("-m7"); // Set option for Csound c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n"); //Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amp = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freq = new RandomLine(400, 80); // create RandomLine for use with Frequency var bus = c.GetSoftwareBus(); //The bus's channels can be accessed by name like a dictionary. //If they don't yet exist, they will be defined (input/output as default) bus["amp"] = amp.Value; //Create and provide and initial value for an amplitude channel bus["freq"] = freq.Value; //Create and provide and initial value for a frequency channel while (!c.PerformKsmps()) { bus["amp"] = amp.Value; bus["freq"] = freq.Value; } c.Stop(); } }
/* Example 7 - Communicating continuous values with Csound's Channel System * * This example introduces using Csound's Channel System to communicate * continuous control data (k-rate) from a host program to Csound. The * first thing to note is the RandomLine class. It takes in a base value * and a range in which to vary randomly. The reset functions calculates * a new random target value (this.End), a random duration in which to * run (this.Dur, expressed as # of audio blocks to last in duration), and * calculates the increment value to apply to the current value per audio-block. * When the target is met, the Randomline will reset itself to a new target * value and duration. * * In this example, we use two RandomLine objects, one for amplitude and * another for frequency. We start a Csound instrument instance that reads * from two channels using the chnget opcode. In turn, we update the values * to the channel from the host program. In this case, because we want to * keep our values generating in sync with the audio engine, we use a * while-loop instead of a CsoundPerformanceThread. To update the channel, * we call the SoftwareBus's channel indexer methods with new values. * * Note: The Value property on the RandomLine objects not only gets * us the current value, but also advances the internal state by the increment * and by decrementing the duration. * * In the C# object wrappers, channels are objects which are most easily used * via a software bus object as this implemetation demonstrates. */ public void Example7() { using (var c = new Csound6NetRealtime()) { c.SetOption("-odac"); // Set option for Csound c.SetOption("-m7"); // Set option for Csound c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n"); //Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amp = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freq = new RandomLine(400, 80); // create RandomLine for use with Frequency var bus = c.GetSoftwareBus(); //Channels can be created explicitly: bus.AddControlChannel("amp", ChannelDirection.Input); bus["amp"] = amp.Value; //Add an initial value: Value property changes after each use //Or channels can be created implicitly just by using it: //The bus's channels can be accessed by name like a dictionary. //If they don't yet exist, they will be defined (input/output as default) bus["freq"] = freq.Value;//Create and provide and initial value in one call //Now we have our channels: update them with new RandomLine values after each ksmps cycle: while (!c.PerformKsmps()) { bus["amp"] = amp.Value; bus["freq"] = freq.Value; } c.Stop(); } }
public void Example9() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); //direct sample output to sound card //SetOptions requires the knowing and using the command line flags and their arguments. //The csound API (and C# bridge) expose another way to set csounds //parameters as properties. This would suit a GUI dialog better than SetOption. var options = c.GetParameters(); //also var options = new Csound6Parameters(c); //You can read their current value: Console.Write(options.Tempo); Console.WriteLine(string.Format("Current Message Level = {0}", options.MessageLevel)); //Instead of SetOptions("-m7"), you can use: options.MessageLevel = MessageLevel.Amps | MessageLevel.Range | MessageLevel.Warnings; //=7 //Using IntelliSense, you can explore the various settings csound exposes (various command line flags). options.IsDebugMode = false; options.Tempo = 120; //will cause 10 in score to be 5 (tempo defaults to 60) c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n");//Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amps = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freqs = new RandomLine(400, 80); // create RandomLine for use with Frequency 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); while (!c.PerformKsmps()) { //continue to update memory for the two channels directly ampChannel.SetValueDirect(amps.Value); freqChannel.SetValueDirect(freqs.Value); } c.Stop(); } }
public void Example9() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); //direct sample output to sound card //SetOptions requires the knowing and using the command line flags and their arguments. //The csound API (and C# bridge) expose another way to set csounds //parameters as properties. This would suit a GUI dialog better than SetOption. var options = c.GetParameters(); //also var options = new Csound6Parameters(c); //You can read their current value: Console.Write(options.Tempo); Console.WriteLine(string.Format("Current Message Level = {0}", options.MessageLevel)); //Instead of SetOptions("-m7"), you can use: options.MessageLevel = MessageLevel.Amps | MessageLevel.Range | MessageLevel.Warnings; //=7 //Using IntelliSense, you can explore the various settings csound exposes (various command line flags). options.IsDebugMode = false; options.Tempo = 120; //will cause 10 in score to be 5 (tempo defaults to 60) c.CompileOrc(orc3); // Compile Orchestra from String c.ReadScore("i1 0 10\n"); //Read in a score to run for 10 seconds c.Start(); //Must call Start() explicitly when compiling from a string var amps = new RandomLine(.4, .2); // create RandomLine for use with Amplitude var freqs = new RandomLine(400, 80); // create RandomLine for use with Frequency 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); while (!c.PerformKsmps()) { //continue to update memory for the two channels directly ampChannel.SetValueDirect(amps.Value); freqChannel.SetValueDirect(freqs.Value); } c.Stop(); } }
public void TestOutInCallbacks() { m_messageText = new StringBuilder(); m_count = 0; m_outval = -1; using (var cs = new Csound6NetRealtime()) { cs.OutputChannelCallback += TestOutputCallback; cs.InputChannelCallback += TestInputCallback; var result = cs.Compile(new string[] { "csdFiles\\SimpleRuntime.csd" }); Assert.AreEqual(CsoundStatus.Success, result); if (result == CsoundStatus.Success) { while (!cs.PerformKsmps()) { ; } } cs.Cleanup(); } }
public void TestChannelDirectAccess() { using (var cs = new Csound6NetRealtime()) { var result = cs.Compile(new string[] { "csdFiles\\SimpleRuntime.csd" }); Assert.AreEqual(CsoundStatus.Success, result); if (result == CsoundStatus.Success) { var bus = cs.GetSoftwareBus(); var chan2 = bus.GetChannel("chan2") as Csound6ControlChannel; chan2.SetValueDirect(chan2.Default); double val = chan2.GetValueDirect(); Assert.AreEqual(chan2.Default, val); while (!cs.PerformKsmps()) { Assert.AreEqual(val, chan2.GetValueDirect()); chan2.SetValueDirect(++val); } } } }
public void TestPerfTimeChannels() { m_messageText = new StringBuilder(); m_count = 0; m_outval = -1; using (var cs = new Csound6NetRealtime()) { var result = cs.Compile(new string[] { "csdFiles\\SimpleRuntime.csd" }); Assert.AreEqual(CsoundStatus.Success, result); if (result == CsoundStatus.Success) { var bus = cs.GetSoftwareBus(); while (!cs.PerformKsmps()) { double[] samps = bus["achan1"] as double[]; double[] sampInv = new double[samps.Length]; if (cs.ScoreTime <= 0.1) { foreach (double samp in samps) { Assert.IsTrue(samp == 0.0); } bool hasPvs = bus.HasChannel("0"); if (hasPvs) { object o = bus["0"]; } } else if (cs.ScoreTime == 0.2) { double prev = -1.0; for (int i = 0; i < 26; i++) { Assert.IsTrue(samps[i] > prev); prev = samps[i]; } for (int i = 26; i < 75; i++) { Assert.IsTrue(prev > samps[i]); prev = samps[i]; } for (int i = 0; i < sampInv.Length; i++) { sampInv[i] = -samps[i]; } bus["achan2"] = sampInv; } else if (cs.ScoreTime == 0.3) { double[] samp2 = bus["achan2"] as double[]; double[] samp3 = bus["achan3"] as double[]; //instrument will have put samp2 into achan3 during 0.2 second; now available in 0.3 sec for (int i = 0; i < samp3.Length; i++) { Assert.AreEqual(samp2[i], samp3[i]); } } } } cs.Cleanup(); } }