/* 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();
            }
        }
Exemple #3
0
        /**
         * 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();

            }
        }
Exemple #8
0
        public void TestSoftwareBus()
        {
            using (var cs = new Csound6NetRealtime())
            {
                var result = cs.Compile(new string[] { "csdFiles\\SimpleRuntime.csd" });
                Assert.AreEqual(CsoundStatus.Success, result);

                var bus = cs.GetSoftwareBus();
                Assert.IsNotNull(bus);
                Assert.IsTrue(bus.Count > 0);
                Assert.AreEqual(8, bus.Count);
                foreach (var channel in bus.Channels)
                {
                    switch (channel.Type)
                    {
                    case ChannelType.Control:
                        Assert.IsTrue(channel.Name.StartsWith("chan"));
                        Assert.IsInstanceOfType(channel, typeof(Csound6ControlChannel));
                        Assert.IsInstanceOfType(channel.Value, typeof(double));
                        Assert.AreEqual(channel.Value, bus[channel.Name]);
                        break;

                    case ChannelType.String:
                        Assert.IsInstanceOfType(channel, typeof(Csound6StringChannel));
                        Assert.IsInstanceOfType(channel.Value, typeof(string));
                        Assert.IsTrue(channel.Name.StartsWith("schan"));
                        Assert.AreEqual(channel.Value, bus[channel.Name]);
                        break;

                    case ChannelType.Audio:
                        Assert.IsInstanceOfType(channel, typeof(Csound6AudioChannel));
                        Assert.IsTrue(channel.Name.StartsWith("achan"));
                        Assert.IsInstanceOfType(channel.Value, typeof(double[]));
                        var values = channel.Value as double[];
                        Assert.AreEqual(cs.Ksmps, values.Length);
                        break;

                    case ChannelType.Pvs:
                        Assert.Fail("PVS data type not yet supported in .net");
                        break;

                    default:
                        Assert.Fail(string.Format("Software bus has unsupported channel {0} of type: {1}", channel.Name, channel.Type));
                        break;
                    }
                }
            }
        }
Exemple #9
0
        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();
            }
        }
Exemple #10
0
        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);
                    }
                }
            }
        }
Exemple #11
0
 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();
     }
 }
Exemple #12
0
 /// <summary>
 /// Convenience indexer for accessing software bus channel values by name.
 /// </summary>
 /// <param name="channel">the name of a valid channel on the software bus in the current score</param>
 /// <returns></returns>
 public object this[string channel]
 {
     get { return(Csound.GetSoftwareBus()[channel]); }
     set { Csound.GetSoftwareBus()[channel] = value; }
 }