/* 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 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 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 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 (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(); } }
/** * Example 4 - Using Csound's Performance Thread * Example 4.1 - Using Csound in a C# async/await Task for threaded execution * * In this example, we use a CsoundPerformanceThread to run Csound in * a native thread. Using a native thread is important to get the best * runtime performance for the audio engine. * CsoundPerformanceThread has some convenient methods for handling events, * but does not have features for doing regular processing at block boundaries. * In general, use CsoundPerformanceThread when the only kinds of communication you * are doing with Csound are through events, and not using channels. * * Since VS2012, C# programmers have become comfortable with the async/await Task-based * paradigm for running background processes. * Example 4.1 shows an alternative to running csound in a separate thread (really Task) * to achieve the same result as example 4. * This approach is very useful in a GUI where a cancel event and a progress dialog * would be desireable. * This example bypasses these features; later examples will use them. */ public void Example4() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); // Set realtime output for Csound c.CompileOrc(orc); // Compile Orchestra from String c.ReadScore("i1 0 1"); // Read in Score from String c.Start(); // When compiling from strings, this call needed before performing // Create a new CsoundPerformanceThread, passing in the Csound object var t = new Csound6PerformanceThread(c); t.Play(); // starts the thread, which is now running separately from the main thread. This // call is asynchronous and will immediately return back here to continue code // execution. t.Join(); // Join will wait for the other thread to complete. If we did not call Join(), // after t.Play() returns we would immediate move to the next line, c.Stop(). // That would stop Csound without really giving it time to run. c.Stop(); // stops Csound c.Cleanup();// clean up Csound; this is useful if you're going to reuse a Csound instance } }
/** * Example 4 - Using Csound's Performance Thread * Example 4.1 - Using Csound in a C# async/await Task for threaded execution * * In this example, we use a CsoundPerformanceThread to run Csound in * a native thread. Using a native thread is important to get the best * runtime performance for the audio engine. * CsoundPerformanceThread has some convenient methods for handling events, * but does not have features for doing regular processing at block boundaries. * In general, use CsoundPerformanceThread when the only kinds of communication you * are doing with Csound are through events, and not using channels. * * Since VS2012, C# programmers have become comfortable with the async/await Task-based * paradigm for running background processes. * Example 4.1 shows an alternative to running csound in a separate thread (really Task) * to achieve the same result as example 4. * This approach is very useful in a GUI where a cancel event and a progress dialog * would be desireable. * This example bypasses these features; later examples will use them. */ public void Example4() { using (var c = new Csound6NetRealtime()) { c.SetOutputDac(0); // Set realtime output for Csound c.CompileOrc(orc); // Compile Orchestra from String c.ReadScore("i1 0 1"); // Read in Score from String c.Start(); // When compiling from strings, this call needed before performing // Create a new CsoundPerformanceThread, passing in the Csound object var t = new Csound6PerformanceThread(c); t.Play(); // starts the thread, which is now running separately from the main thread. This // call is asynchronous and will immediately return back here to continue code // execution. t.Join(); // Join will wait for the other thread to complete. If we did not call Join(), // after t.Play() returns we would immediate move to the next line, c.Stop(). // That would stop Csound without really giving it time to run. c.Stop(); // stops Csound c.Cleanup(); // clean up Csound; this is useful if you're going to reuse a Csound instance } }