CsoundUnity 3.4.0
https://github.com/rorywalsh/CsoundUnity
CsoundUnity.cs
Go to the documentation of this file.
1/*
2Copyright (C) 2015 Rory Walsh.
3
4This file is part of CsoundUnity: https://github.com/rorywalsh/CsoundUnity
5
6This interface would not have been possible without Richard Henninger's .NET interface to the Csound API.
7
8Contributors:
9
10Bernt Isak Wærstad
11Charles Berman
12Giovanni Bedetti
13Hector Centeno
14NPatch
15
16Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
17to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
18and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
25THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26*/
27
28using UnityEngine;
29using System.IO;
30using System.Collections.Generic;
31using System.Collections;
32using System;
33using System.Globalization;
34using UnityEngine.Networking;
35#if UNITY_EDITOR
36using UnityEditor;
37#endif
38#if UNITY_EDITOR || UNITY_STANDALONE
39using MYFLT = System.Double;
40#elif UNITY_ANDROID || UNITY_IOS
41using MYFLT = System.Single;
42#endif
43
44#region PUBLIC_CLASSES
45
46[Serializable]
51{
52 [SerializeField] public string type = "";
53 [SerializeField] public string channel = "";
54 [SerializeField] public string text = "";
55 [SerializeField] public string caption = "";
56 [SerializeField] public float min;
57 [SerializeField] public float max;
58 [SerializeField] public float value;
59 [SerializeField] public float skew;
60 [SerializeField] public float increment;
61 [SerializeField] public string[] options;
62
63 public void SetRange(float uMin, float uMax, float uValue = 0f, float uSkew = 1f, float uIncrement = 0.01f)
64 {
65 min = uMin;
66 max = uMax;
67 value = uValue;
68 skew = uSkew;
69 increment = uIncrement;
70 }
71
73 {
74 return this.MemberwiseClone() as CsoundChannelController;
75 }
76
77 //public static explicit operator UnityEngine.Object(CsoundChannelController v)
78 //{
79 // return (UnityEngine.Object)v;
80 //}
81}
82
86[Serializable]
88{
89 [SerializeField] public SupportedPlatform platform;
90 [SerializeField] public CsoundUnity.EnvType type;
91 [SerializeField] public EnvironmentPathOrigin baseFolder;
92 [SerializeField] public string suffix;
93 [Tooltip("Utility bool to store if the drawn property is foldout or not")]
94 [SerializeField] public bool foldout;
95
101 public string GetPath(bool runtime = false)
102 {
103 var path = string.Empty;
104 //Debug.Log($"EnvironmentSettings GetPath from {baseFolder}");
105 switch (baseFolder)
106 {
107 case EnvironmentPathOrigin.PersistentDataPath:
108 path = GetPersistentDataPath(platform, runtime);
109 break;
110 case EnvironmentPathOrigin.StreamingAssets:
111 path = GetStreamingAssetsPath(platform, runtime);
112 break;
113 case EnvironmentPathOrigin.Plugins:
114 path = GetPluginsPath(platform, runtime);
115 break;
116 case EnvironmentPathOrigin.Absolute:
117 default:
118 break;
119 }
120 path = Path.Combine(path, suffix);
121 return path;
122 }
123
128 private string GetPersistentDataPath(SupportedPlatform supportedPlatform, bool runtime)
129 {
130 var res = Application.persistentDataPath;
131 switch (supportedPlatform)
132 {
133 case SupportedPlatform.MacOS:
134 res = runtime ?
135 $"~/Library/Application Support/{Application.companyName}/{Application.productName}" :
136 Application.persistentDataPath;
137 break;
138 case SupportedPlatform.Windows:
139 res = runtime ?
140 $"%userprofile%\\AppData\\LocalLow\\{Application.companyName}\\{Application.productName}" :
141 Application.persistentDataPath;
142 break;
143 case SupportedPlatform.Android:
144 res = runtime ?
145 $"/storage/emulated/0/Android/data/{Application.identifier}/files" : Application.persistentDataPath;
146 break;
147 case SupportedPlatform.iOS:
148 res = runtime ? $"/var/mobile/Containers/Data/Application/{Application.identifier}/Documents" : Application.persistentDataPath;
149 break;
150 }
151 return res;
152 }
153
157 private string GetStreamingAssetsPath(SupportedPlatform supportedPlatform, bool runtime)
158 {
159 var res = Application.streamingAssetsPath;
160 switch (supportedPlatform)
161 {
162 case SupportedPlatform.MacOS:
163 res = runtime ? $"<path to player app bundle>/Contents/Resources/Data/StreamingAssets" : Application.streamingAssetsPath;
164 break;
165 case SupportedPlatform.Windows:
166 res = runtime ? $"<path to executablename_Data folder>" : Application.streamingAssetsPath;
167 break;
168 case SupportedPlatform.Android:
169 res = runtime ? $"jar:file://storage/emulated/0/Android/data/{Application.identifier}/!/assets" : Application.streamingAssetsPath;
170 break;
171 case SupportedPlatform.iOS:
172 res = runtime ? $"/var/mobile/Containers/Data/Application/{Application.identifier}/Raw/" : Application.streamingAssetsPath;
173 break;
174 }
175 return res;
176 }
177
178 private string GetPluginsPath(SupportedPlatform supportedPlatform, bool runtime)
179 {
180 //Debug.Log($"GetPluginsPath for platform: {supportedPlatform}");
181 var res = Path.Combine(Application.dataPath, "Plugins");
182 switch (supportedPlatform)
183 {
184 case SupportedPlatform.MacOS:
185 res = runtime ? $"<path to player app bundle>/Contents/Resources/Data/Plugins" : res;
186 break;
187 case SupportedPlatform.Windows:
188 res = runtime ? $"<path to executablename_Data folder>/Managed" : Path.Combine(Application.dataPath, "Managed");
189 break;
190 case SupportedPlatform.Android:
191#if UNITY_ANDROID && !UNITY_EDITOR
192 //Debug.Log("1 - GET ANDROID NATIVE LIBRARY DIR");
193 res = GetAndroidNativeLibraryDir();
194#else
195 res = runtime ? $"/data/app/<random chars>/{Application.identifier}-<random chars>/lib/arm64-v8a" : res;
196#endif
197 break;
198 case SupportedPlatform.iOS:
199 res = runtime ? $"/var/mobile/Containers/Data/Application/{Application.identifier}/Plugins" : res;
200 break;
201 }
202 return res;
203 }
204
205
206#if UNITY_ANDROID && !UNITY_EDITOR
207 public static AndroidJavaObject GetUnityActivity()
208 {
209 using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
210 {
211 return unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
212 }
213 }
214
215 public static AndroidJavaObject GetUnityContext()
216 {
217 var activity = GetUnityActivity();
218 //Debug.Log($"2 - GetUnityContext, activity null? {activity == null}");
219 return activity.Call<AndroidJavaObject>("getApplicationContext");
220 }
221
222 public static AndroidJavaObject GetApplicationInfo()
223 {
224 var context = GetUnityContext();
225 //Debug.Log($"3 - GetApplicationInfo, context null? {context == null}");
226 return GetUnityContext().Call<AndroidJavaObject>("getApplicationInfo");
227 }
228
229 public static string GetAndroidNativeLibraryDir()
230 {
231 var info = GetApplicationInfo();
232 //Debug.Log($"4 - GetAndroidNativeLibraryDir, info null? {info == null}");
233 return info.Get<string>("nativeLibraryDir");
234 }
235#endif
236
237 public string GetTypeString()
238 {
239 return type.ToString();
240 }
241
242 public string GetPlatformString()
243 {
244 return platform.ToString();
245 }
246
247 public string GetPathDescriptor(bool runtime)
248 {
249 return $"[{GetPlatformString()}]:[{GetTypeString()}]: {GetPath(runtime)}";
250 }
251}
252
253[Serializable]
255
259[Serializable]
261
262#endregion PUBLIC_CLASSES
263
267[AddComponentMenu("Audio/CsoundUnity")]
268[Serializable]
269[RequireComponent(typeof(AudioSource))]
270public class CsoundUnity : MonoBehaviour
271{
272 #region PUBLIC_FIELDS
273
277 public const string packageName = "com.csound.csoundunity";
278
282 public const string packageVersion = "3.4.0";
283
287 public string csoundFileGUID { get => _csoundFileGUID; }
288
294 public string csoundFileName { get => _csoundFileName; }
295
299 public string csoundString { get => _csoundString; }
300
301#if UNITY_EDITOR
305 //[SerializeField]
306 public DefaultAsset csoundAsset { get => _csoundAsset; }
307#endif
308
315 [HideInInspector] public bool logCsoundOutput = false;
316
320 [HideInInspector] public bool mute = false;
321
326 [HideInInspector] public bool processClipAudio;
327
332 [HideInInspector] public bool loudVolumeWarning = true;
333
338 [HideInInspector] public float loudWarningThreshold = 10f;
339
343 public List<CsoundChannelController> channels { get => _channels; }
344
348 public List<string> availableAudioChannels { get => _availableAudioChannels; }
349
353 public readonly Dictionary<string, MYFLT[]> namedAudioChannelDataDict = new Dictionary<string, MYFLT[]>();
354
358 public bool IsInitialized { get => initialized; }
359
363 public delegate void CsoundInitialized();
368
369 public bool PerformanceFinished { get => performanceFinished; }
373 [HideInInspector] public string csoundScore;
374
380 [SerializeField]
381 [HideInInspector]
382 public List<EnvironmentSettings> environmentSettings = new List<EnvironmentSettings>();
383
387 public string CurrentPreset => _currentPreset;
388
389 #endregion PUBLIC_FIELDS
390
391 #region PRIVATE_FIELDS
392
401 private CsoundUnityBridge csound;
402 [HideInInspector] [SerializeField] private string _csoundFileGUID;
403 [HideInInspector] [SerializeField] private string _csoundString;
404 [HideInInspector] [SerializeField] private string _csoundFileName;
405#if UNITY_EDITOR
406 [HideInInspector] [SerializeField] private DefaultAsset _csoundAsset;
407#endif
408 [HideInInspector] [SerializeField] private List<CsoundChannelController> _channels = new List<CsoundChannelController>();
412 private Dictionary<string, int> _channelsIndexDict = new Dictionary<string, int>();
413 [HideInInspector] [SerializeField] private List<string> _availableAudioChannels = new List<string>();
417#pragma warning disable 414
418 [HideInInspector] [SerializeField] private bool _drawCsoundString = false;
419 [HideInInspector] [SerializeField] private bool _drawTestScore = false;
420 [HideInInspector] [SerializeField] private bool _drawSettings = false;
421 [HideInInspector] [SerializeField] private bool _drawChannels = false;
422 [HideInInspector] [SerializeField] private bool _drawAudioChannels = false;
423 [HideInInspector] [SerializeField] private bool _drawPresets = false;
424 [HideInInspector] [SerializeField] private bool _drawPresetsLoad = false;
425 [HideInInspector] [SerializeField] private bool _drawPresetsSave = false;
426 [HideInInspector] [SerializeField] private bool _drawPresetsImport = false;
432 [HideInInspector] [SerializeField] private bool _showRuntimeEnvironmentPath = false;
433 [HideInInspector] [SerializeField] private string _currentPreset;
434 [HideInInspector] [SerializeField] private string _currentPresetSaveFolder;
435 [HideInInspector] [SerializeField] private string _currentPresetLoadFolder;
436
437
438
439#pragma warning restore 414
440
441 private bool initialized = false;
442 private uint ksmps = 32;
443 private uint ksmpsIndex = 0;
444 private float zerdbfs = 1;
445 private bool compiledOk = false;
446 private bool performanceFinished;
447 private AudioSource audioSource;
448 private Coroutine LoggingCoroutine;
449 int bufferSize, numBuffers;
450
451 private const string GLOBAL_TAG = "(GLOBAL)";
452
456 private Dictionary<string, MYFLT[]> namedAudioChannelTempBufferDict = new Dictionary<string, MYFLT[]>();
457
458 #endregion
459
467 void Awake()
468 {
469 initialized = false;
470
471 AudioSettings.GetDSPBufferSize(out bufferSize, out numBuffers);
472
473 audioSource = GetComponent<AudioSource>();
474 audioSource.spatializePostEffects = true;
475
476 // FIX SPATIALIZATION ISSUES
477 if (audioSource.clip == null && !processClipAudio)
478 {
479 var ac = AudioClip.Create("CsoundUnitySpatializerClip", 32, 1, AudioSettings.outputSampleRate, false);
480 var data = new float[32];
481 for (var i = 0; i < data.Length; i++) data[i] = 1;
482 ac.SetData(data, 0);
483
484 audioSource.clip = ac;
485 audioSource.loop = true;
486 audioSource.Play();
487 }
488
492 csound = new CsoundUnityBridge(_csoundString, environmentSettings);
493 if (csound != null)
494 {
496 if (channels != null)
497 // initialise channels if found in xml descriptor..
498 for (int i = 0; i < channels.Count; i++)
499 {
500 if (channels[i].type.Contains("combobox"))
501 csound.SetChannel(channels[i].channel, channels[i].value + 1);
502 else
503 csound.SetChannel(channels[i].channel, channels[i].value);
504 // update channels index dictionary
505 if (!_channelsIndexDict.ContainsKey(channels[i].channel))
506 _channelsIndexDict.Add(channels[i].channel, i);
507 }
508
509 foreach (var name in availableAudioChannels)
510 {
511 if (!namedAudioChannelDataDict.ContainsKey(name))
512 {
513 namedAudioChannelDataDict.Add(name, new MYFLT[bufferSize]);
514 namedAudioChannelTempBufferDict.Add(name, new MYFLT[ksmps]);
515 }
516 }
517
519 LoggingCoroutine = StartCoroutine(Logging(.01f));
520
521 compiledOk = csound.CompiledWithoutError();
522
523 if (compiledOk)
524 {
525 zerdbfs = (float)csound.Get0dbfs();
526
527 Debug.Log($"Csound zerdbfs: {zerdbfs}");
528
529 initialized = true;
530 OnCsoundInitialized?.Invoke();
531 }
532 }
533 else
534 {
535 Debug.Log("Error creating Csound object");
536 compiledOk = false;
537 }
538
539 Debug.Log($"CsoundUnity done init, compiledOk? {compiledOk}");
540 }
541
542 #region PUBLIC_METHODS
543
544 #region INSTANTIATION
545
550 public int GetVersion()
551 {
552 return csound.GetVersion();
553 }
554
559 public int GetAPIVersion()
560 {
561 return csound.GetAPIVersion();
562 }
563
569 public int LoadPlugins(string dir)
570 {
571 return csound.LoadPlugins(dir);
572 }
573
579 {
580 return compiledOk;
581 }
582
583 #endregion INSTANTIATION
584
585 #region PERFORMANCE
586
591 public void SetCsd(string guid)
592 {
593#if UNITY_EDITOR //for now setting csd is permitted from editor only, via asset guid
594
595 // Debug.Log($"SET CSD guid: {guid}");
596 if (string.IsNullOrWhiteSpace(guid) || !Guid.TryParse(guid, out Guid guidResult))
597 {
598 Debug.LogWarning($"GUID NOT VALID, Resetting fields");
599 ResetFields();
600 return;
601 }
602
603 var fileName = AssetDatabase.GUIDToAssetPath(guid);
604
605 if (string.IsNullOrWhiteSpace(fileName) ||
606 fileName.Length < 4 ||
607 Path.GetFileName(fileName).Length < 4 ||
608 !Path.GetFileName(fileName).EndsWith(".csd"))
609 {
610 Debug.LogWarning("FILENAME not valid, Resetting fields");
611 ResetFields();
612 return;
613 }
614
615 this._csoundFileGUID = guid;
616 this._csoundFileName = Path.GetFileName(fileName);
617 var csoundFilePath = Path.GetFullPath(fileName);
618 this._csoundAsset = (DefaultAsset)(AssetDatabase.LoadAssetAtPath(fileName, typeof(DefaultAsset)));
619 this._csoundString = File.ReadAllText(csoundFilePath);
620 this._channels = ParseCsdFile(fileName);
621 var count = 0;
622 foreach (var chan in this._channels)
623 if (!_channelsIndexDict.ContainsKey(chan.channel))
624 _channelsIndexDict.Add(chan.channel, count++);
625 this._availableAudioChannels = ParseCsdFileForAudioChannels(fileName);
626
627 foreach (var name in availableAudioChannels)
628 {
629 if (string.IsNullOrWhiteSpace(name)) continue;
630
631 if (!namedAudioChannelDataDict.ContainsKey(name))
632 {
633 namedAudioChannelDataDict.Add(name, new MYFLT[bufferSize]);
634 namedAudioChannelTempBufferDict.Add(name, new MYFLT[ksmps]);
635 }
636 }
637
638#endif
639 }
640
655 public int CompileOrc(string orcStr)
656 {
657 return csound.CompileOrc(orcStr);
658 }
659
664 public void SendScoreEvent(string scoreEvent)
665 {
666 //print(scoreEvent);
667 csound.SendScoreEvent(scoreEvent);
668 }
669
673 public void RewindScore()
674 {
675 csound.RewindScore();
676 }
677
686 public void SetScoreOffsetSeconds(MYFLT value)
687 {
688 csound.CsoundSetScoreOffsetSeconds(value);
689 }
690
695 public MYFLT GetSr()
696 {
697 return csound.GetSr();
698 }
699
704 public MYFLT GetKr()
705 {
706 return csound.GetKr();
707 }
708
713 public int PerformKsmps()
714 {
715 return csound.PerformKsmps();
716 }
717
722 public uint GetKsmps()
723 {
724 return csound.GetKsmps();
725 }
726
727 #endregion PERFORMANCE
728
729 #region CSD_PARSE
730
736 public static List<string> ParseCsdFileForAudioChannels(string filename)
737 {
738 if (!File.Exists(filename)) return null;
739
740 string[] fullCsdText = File.ReadAllLines(filename);
741 if (fullCsdText.Length < 1) return null;
742
743 List<string> locaAudioChannels = new List<string>();
744
745 foreach (string line in fullCsdText)
746 {
747 var trimmd = line.TrimStart();
748 if (!trimmd.Contains("chnset")) continue;
749 if (trimmd.StartsWith(";")) continue;
750 var lndx = trimmd.IndexOf("chnset");
751 var chnsetEnd = lndx + "chnset".Length + 1;
752 var prms = trimmd.Substring(chnsetEnd, trimmd.Length - chnsetEnd);
753 var split = prms.Split(',');
754 if (!split[0].StartsWith("a") && !split[0].StartsWith("ga"))
755 continue; //discard non audio variables
756 // Debug.Log("found audio channel");
757 var ach = split[1].Replace('\\', ' ').Replace('\"', ' ').Trim();
758 if (!locaAudioChannels.Contains(ach))
759 locaAudioChannels.Add(ach);
760 }
761 return locaAudioChannels;
762 }
763
769 public static List<CsoundChannelController> ParseCsdFile(string filename)
770 {
771 if (!File.Exists(filename)) return null;
772
773 string[] fullCsdText = File.ReadAllLines(filename);
774 if (fullCsdText.Length < 1) return null;
775
776 List<CsoundChannelController> locaChannelControllers;
777 locaChannelControllers = new List<CsoundChannelController>();
778
779 foreach (string line in fullCsdText)
780 {
781
782 if (line.Contains("</"))
783 break;
784
785 var trimmd = line.TrimStart();
786 //discard csound comments in cabbage widgets
787 if (trimmd.StartsWith(";"))
788 {
789 //Debug.Log("discarding "+line);
790 continue;
791 }
792 var control = trimmd.Substring(0, trimmd.IndexOf(" ") > -1 ? trimmd.IndexOf(" ") : 0);
793 if (control.Contains("slider") || control.Contains("button") || control.Contains("checkbox")
794 || control.Contains("groupbox") || control.Contains("form") || control.Contains("combobox"))
795 {
797 controller.type = control;
798 if (trimmd.IndexOf("caption(") > -1)
799 {
800 string infoText = trimmd.Substring(trimmd.IndexOf("caption(") + 9);
801 infoText = infoText.Substring(0, infoText.IndexOf(")") - 1);
802 controller.caption = infoText;
803 }
804
805 if (trimmd.IndexOf("text(") > -1)
806 {
807 string text = trimmd.Substring(trimmd.IndexOf("text(") + 6);
808 text = text.Substring(0, text.IndexOf(")") - 1);
809 text = text.Replace("\"", "");
810 text = text.Replace('"', new char());
811 controller.text = text;
812 if (controller.type == "combobox") //if combobox, create a range
813 {
814 char[] delimiterChars = { ',' };
815 string[] tokens = text.Split(delimiterChars);
816 controller.SetRange(1, tokens.Length, 0);
817
818 for (var o = 0; o < tokens.Length; o++)
819 {
820 tokens[o] = string.Join("", tokens[o].Split(default(string[]), System.StringSplitOptions.RemoveEmptyEntries));
821 }
822 controller.options = tokens;
823 }
824 }
825
826 if (trimmd.IndexOf("items(") > -1)
827 {
828 string text = trimmd.Substring(trimmd.IndexOf("items(") + 7);
829 text = text.Substring(0, text.IndexOf(")") - 1);
830 //TODO THIS OVERRIDES TEXT!
831 text = text.Replace("\"", "");
832 text = text.Replace('"', new char());
833 if (controller.type == "combobox")
834 {
835 char[] delimiterChars = { ',' };
836 string[] tokens = text.Split(delimiterChars);
837 controller.SetRange(1, tokens.Length, 0);
838
839 for (var o = 0; o < tokens.Length; o++)
840 {
841 tokens[o] = string.Join("", tokens[o].Split(default(string[]), System.StringSplitOptions.RemoveEmptyEntries));
842 }
843 controller.options = tokens;
844 }
845 }
846
847 if (trimmd.IndexOf("channel(") > -1)
848 {
849 string channel = trimmd.Substring(trimmd.IndexOf("channel(") + 9);
850 channel = channel.Substring(0, channel.IndexOf(")") - 1);
851 controller.channel = channel;
852 }
853
854 if (trimmd.IndexOf("range(") > -1)
855 {
856 int rangeAt = trimmd.IndexOf("range(");
857 if (rangeAt != -1)
858 {
859 string range = trimmd.Substring(rangeAt + 6);
860 range = range.Substring(0, range.IndexOf(")"));
861 char[] delimiterChars = { ',' };
862 string[] tokens = range.Split(delimiterChars);
863 for (var i = 0; i < tokens.Length; i++)
864 {
865 tokens[i] = string.Join("", tokens[i].Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
866 if (tokens[i].StartsWith("."))
867 {
868 tokens[i] = "0" + tokens[i];
869 }
870 if (tokens[i].StartsWith("-."))
871 {
872 tokens[i] = "-0" + tokens[i].Substring(2, tokens[i].Length - 2);
873 }
874 }
875 var min = float.Parse(tokens[0], CultureInfo.InvariantCulture);
876 var max = float.Parse(tokens[1], CultureInfo.InvariantCulture);
877 var val = 0f;
878 var skew = 1f;
879 var increment = 1f;
880
881 if (tokens.Length > 2)
882 {
883 val = float.Parse(tokens[2], CultureInfo.InvariantCulture);
884 }
885 if (tokens.Length > 3)
886 {
887 skew = float.Parse(tokens[3], CultureInfo.InvariantCulture);
888 }
889 if (tokens.Length > 4)
890 {
891 increment = float.Parse(tokens[4], CultureInfo.InvariantCulture);
892 }
893 // Debug.Log($"{tokens.Length}");
894 controller.SetRange(min, max, val, skew, increment);
895 }
896 }
897
898 if (line.IndexOf("value(") > -1)
899 {
900 string value = trimmd.Substring(trimmd.IndexOf("value(") + 6);
901 value = value.Substring(0, value.IndexOf(")"));
902 value = value.Replace("\"", "");
903 controller.value = value.Length > 0 ? float.Parse(value, CultureInfo.InvariantCulture) : 0;
904 if (control.Contains("combobox"))
905 {
906 //Cabbage combobox index starts from 1
907 controller.value = controller.value - 1;
908 // Debug.Log("combobox value in parse: " + controller.value);
909 }
910 }
911 locaChannelControllers.Add(controller);
912 }
913 }
914 return locaChannelControllers;
915 }
916
917 #endregion CSD_PARSE
918
919 #region IO_BUFFERS
920
927 public void SetInputSample(int frame, int channel, MYFLT sample)
928 {
929 csound.SetSpinSample(frame, channel, sample);
930 }
931
941 public void AddInputSample(int frame, int channel, MYFLT sample)
942 {
943 csound.AddSpinSample(frame, channel, sample);
944 }
945
949 public void ClearSpin()
950 {
951 if (csound != null)
952 {
953 Debug.Log("clear spin");
954 csound.ClearSpin();
955 }
956 }
957
964 public MYFLT GetOutputSample(int frame, int channel)
965 {
966 return csound.GetSpoutSample(frame, channel);
967 }
968
973 public MYFLT[] GetSpin()
974 {
975 return csound.GetSpin();
976 }
977
982 public MYFLT[] GetSpout()
983 {
984 return csound.GetSpout();
985 }
986
987 #endregion IO_BUFFERS
988
989 #region CONTROL_CHANNELS
995 public void SetChannel(string channel, MYFLT val)
996 {
997 csound.SetChannel(channel, val);
998
999 // The dictionary below is used to update the serialized channels on the editor
1000 // Please note that on Cabbage comboboxes values go from 1-n, since 0 refers to no current selection,
1001 // instead on the Unity Editor their values start from 0
1002 // so the value on the serialized channel will be decreased by one
1003 if (_channelsIndexDict.ContainsKey(channel))
1004 {
1005 if (channels[_channelsIndexDict[channel]].type.Contains("combobox"))
1006 {
1007 val--;
1008 }
1009 channels[_channelsIndexDict[channel]].value = (float)val;
1010 }
1011 }
1012
1017 public void SetChannel(CsoundChannelController channelController)
1018 {
1019 if (_channelsIndexDict.ContainsKey(channelController.channel))
1020 channels[_channelsIndexDict[channelController.channel]] = channelController;
1021 if (csound == null) return;
1022 csound.SetChannel(channelController.channel, channelController.value);
1023 }
1024
1030 public void SetChannels(List<CsoundChannelController> channelControllers, bool excludeButtons = true)
1031 {
1032 for (var i = 0; i < channelControllers.Count; i++)
1033 {
1034 if (excludeButtons && channelControllers[i].type.Contains("button")) continue;
1035
1036 SetChannel(channelControllers[i]);
1037 }
1038 }
1039
1045 public void SetStringChannel(string channel, string val)
1046 {
1047 csound.SetStringChannel(channel, val);
1048 }
1049
1055 public MYFLT GetChannel(string channel)
1056 {
1057 return csound.GetChannel(channel);
1058 }
1059
1066 {
1067 if (!_channelsIndexDict.ContainsKey(channel)) return null;
1068 var indx = _channelsIndexDict[channel];
1069 return this._channels[indx];
1070 }
1079 public IDictionary<string, CsoundUnityBridge.ChannelInfo> GetChannelList()
1080 {
1081 return csound.GetChannelList();
1082 }
1083
1084 #endregion CONTROL_CHANNELS
1085
1086 #region AUDIO_CHANNELS
1087
1093 public MYFLT[] GetAudioChannel(string channel)
1094 {
1095 return csound.GetAudioChannel(channel);
1096 }
1097
1098 #endregion AUDIO_CHANNELS
1099
1100 #region TABLES
1101
1109 public int CreateFloatTable(int tableNumber, float[] samples)
1110 {
1111 var myFlts = ConvertToMYFLT(samples);
1112 return CreateTable(tableNumber, myFlts);
1113 }
1114
1122 public int CreateTable(int tableNumber, MYFLT[] samples)
1123 {
1124 if (samples.Length < 1) return -1;
1125 var resTable = CreateTableInstrument(tableNumber, samples.Length);
1126 if (resTable != 0)
1127 return -1;
1128 // copy samples to the newly created table
1129 CopyTableIn(tableNumber, samples);
1130
1131 return resTable;
1132 }
1133
1142 public int CreateTableInstrument(int tableNumber, int tableLength)
1143 {
1144 string createTableInstrument = String.Format(@"gisampletable{0} ftgen {0}, 0, {1}, -7, 0, 0", tableNumber, -tableLength );
1145 // Debug.Log("orc to create table: \n" + createTableInstrument);
1146 return CompileOrc(createTableInstrument);
1147 }
1148
1154 public int GetTableLength(int table)
1155 {
1156 return csound.TableLength(table);
1157 }
1158
1165 public MYFLT GetTableSample(int tableNumber, int index)
1166 {
1167 return csound.GetTable(tableNumber, index);
1168 }
1169
1177 public int GetTable(out MYFLT[] tableValues, int numTable)
1178 {
1179 return csound.GetTable(out tableValues, numTable);
1180 }
1181
1191 public int GetTableArgs(out MYFLT[] args, int index)
1192 {
1193 return csound.GetTableArgs(out args, index);
1194 }
1195
1202 public void SetTable(int table, int index, MYFLT value)
1203 {
1204 csound.SetTable(table, index, value);
1205 }
1206
1213 public void CopyTableOut(int table, out MYFLT[] dest)
1214 {
1215 csound.TableCopyOut(table, out dest);
1216 }
1217
1223 public void CopyTableOutAsync(int table, out MYFLT[] dest)
1224 {
1225 csound.TableCopyOutAsync(table, out dest);
1226 }
1227
1233 public void CopyFloatTableIn(int table, float[] source)
1234 {
1235 var myFlts = ConvertToMYFLT(source);
1236 CopyTableIn(table, myFlts);
1237 }
1238
1245 public void CopyTableIn(int table, MYFLT[] source)
1246 {
1247 csound.TableCopyIn(table, source);
1248 }
1249
1255 public void CopyTableInAsync(int table, MYFLT[] source)
1256 {
1257 csound.TableCopyInAsync(table, source);
1258 }
1259
1266 public int IsNamedGEN(int num)
1267 {
1268 return csound.IsNamedGEN(num);
1269 }
1270
1278 public void GetNamedGEN(int num, out string name, int len)
1279 {
1280 csound.GetNamedGEN(num, out name, len);
1281 }
1282
1288 public IDictionary<string, int> GetNamedGens()
1289 {
1290 return csound.GetNamedGens();
1291 }
1292
1293 #endregion TABLES
1294
1295 #region UTILITIES
1296
1297#if UNITY_EDITOR
1302 public string GetFilePath()
1303 {
1304 return Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length), AssetDatabase.GUIDToAssetPath(csoundFileGUID));
1305 }
1306#endif
1307
1315 {
1316 return csound.GetParams();
1317 }
1318
1329 {
1330 csound.SetParams(parms);
1331 }
1332
1338 public string GetEnv(EnvType envType)
1339 {
1340 return csound.GetEnv(envType.ToString());
1341 }
1342
1351 public int SetGlobalEnv(string name, string value)
1352 {
1353 return csound.SetGlobalEnv(name, value);
1354 }
1355
1360 public IDictionary<string, IList<CsoundUnityBridge.OpcodeArgumentTypes>> GetOpcodeList()
1361 {
1362 return csound.GetOpcodeList();
1363 }
1364
1369 public uint GetNchnlsInputs()
1370 {
1371 return csound.GetNchnlsInput();
1372 }
1373
1378 public uint GetNchnls()
1379 {
1380 return csound.GetNchnls();
1381 }
1382
1387 public MYFLT Get0dbfs()
1388 {
1389 return csound.Get0dbfs();
1390 }
1391
1397 {
1398 return csound.GetCurrentTimeSamples();
1399 }
1400
1410 public static float Remap(float value, float from1, float to1, float from2, float to2, bool clamp = false)
1411 {
1412 float retValue = (value - from1) / (to1 - from1) * (to2 - from2) + from2;
1413 if (float.IsNaN(retValue)) return from2;
1414 if (float.IsPositiveInfinity(retValue)) return to2;
1415 if (float.IsNegativeInfinity(retValue)) return from2;
1416 return clamp ? Mathf.Clamp(retValue, from2, to2) : retValue;
1417 }
1418
1429 public static float RemapTo0to1(float value, float from, float to, float skew = 1f)
1430 {
1431 if ((to - from) == 0) return 0;
1432
1433 var proportion = Mathf.Clamp01((value - from) / (to - from));
1434
1435 if (skew == 1)
1436 return proportion;
1437
1438 return Mathf.Pow(proportion, skew);
1439 }
1440
1441
1452 public static float RemapFrom0to1(float value, float from, float to, float skew = 1f)
1453 {
1454 if (skew == 0) return to;
1455
1456 var proportion = Mathf.Clamp01(value);
1457
1458 if (skew != 1 && proportion > 0)
1459 proportion = Mathf.Exp(Mathf.Log(proportion) / skew);
1460
1461 return from + (to - from) * proportion;
1462 }
1463
1469 public static MYFLT[] ConvertToMYFLT(float[] samples)
1470 {
1471 if (samples == null || samples.Length == 0) return new MYFLT[0];
1472 var myFLT = new MYFLT[samples.Length];
1473 for (var i = 0; i < myFLT.Length; i++)
1474 {
1475 myFLT[i] = (MYFLT)samples[i];
1476 }
1477 return myFLT;
1478 }
1479
1485 public static float[] ConvertToFloat(MYFLT[] samples)
1486 {
1487 if (samples == null || samples.Length == 0) return new float[0];
1488 var flt = new float[samples.Length];
1489 for (var i = 0; i < flt.Length; i++)
1490 {
1491 flt[i] = (float)samples[i];
1492 }
1493 return flt;
1494 }
1495
1503 public static MYFLT[] GetStereoSamples(string source)
1504 {
1505 return GetSamples(source, 0, true);
1506 }
1507
1515 public static float[] GetStereoFloatSamples(string source)
1516 {
1517 return ConvertToFloat(GetSamples(source, 0, true));
1518 }
1519
1527 public static MYFLT[] GetMonoSamples(string source, int channelNumber)
1528 {
1529 return GetSamples(source, channelNumber, false);
1530 }
1531
1539 public static float[] GetMonoFloatSamples(string source, int channelNumber)
1540 {
1541 return ConvertToFloat(GetSamples(source, channelNumber, false));
1542 }
1543
1557 public static MYFLT[] GetSamples(string source, int channelNumber = 1, bool writeChannelData = false)
1558 {
1559 MYFLT[] res = new MYFLT[0];
1560
1561 var src = Resources.Load<AudioClip>(source);
1562 if (src == null)
1563 {
1564 Debug.LogError($"Couldn't load samples from AudioClip {source}");
1565 return res;
1566 }
1567
1568 var data = new float[src.samples * src.channels];
1569 src.GetData(data, 0);
1570
1571 if (writeChannelData)
1572 {
1573 res = new MYFLT[src.samples * src.channels + 1];
1574 res[0] = src.channels;
1575 var s = 1;
1576 for (var i = 0; i < data.Length; i++)
1577 {
1578 res[s] = data[i];
1579 s++;
1580 }
1581 }
1582 else
1583 {
1584 var s = 0;
1585 res = new MYFLT[src.samples];
1586
1587 for (var i = 0; i < data.Length; i += src.channels, s++)
1588 {
1589 res[s] = data[i + (channelNumber - 1)];
1590 }
1591 }
1592
1593 return res;
1594 }
1595
1603 public static float[] GetFloatSamples(string source, int channelNumber = 1, bool writeChannelData = false)
1604 {
1605 return ConvertToFloat(GetSamples(source, channelNumber, writeChannelData));
1606 }
1607
1625 public static IEnumerator GetSamples(string source, SamplesOrigin origin, Action<MYFLT[]> onSamplesLoaded)
1626 {
1627 switch (origin)
1628 {
1629 case SamplesOrigin.Resources:
1630 var req = Resources.LoadAsync<AudioClip>(source);
1631
1632 while (!req.isDone)
1633 {
1634 yield return null;
1635 }
1636 var samples = ((AudioClip)req.asset).samples;
1637 if (samples == 0)
1638 {
1639 onSamplesLoaded?.Invoke(null);
1640 yield break;
1641 }
1642 onSamplesLoaded?.Invoke(GetSamples((AudioClip)req.asset));
1643 break;
1644 case SamplesOrigin.StreamingAssets:
1645 var path = Path.Combine(Application.streamingAssetsPath, source);
1646 yield return LoadingClip(path, (clip) =>
1647 {
1648 onSamplesLoaded?.Invoke(GetSamples(clip));
1649 });
1650 break;
1651 case SamplesOrigin.Absolute:
1652 yield return LoadingClip(source, (clip) =>
1653 {
1654 onSamplesLoaded?.Invoke(GetSamples(clip));
1655 });
1656 break;
1657 }
1658 }
1659
1665 public static MYFLT[] GetSamples(AudioClip audioClip)
1666 {
1667 var data = new float[audioClip.samples * audioClip.channels];
1668 audioClip.GetData(data, 0);
1669 MYFLT[] res = new MYFLT[data.Length];
1670 var s = 0;
1671 foreach (var d in data)
1672 {
1673 res[s] = (MYFLT)d;
1674 s++;
1675 }
1676 return res;
1677 }
1678
1679 static IEnumerator LoadingClip(string path, Action<AudioClip> onEnd)
1680 {
1681 var ext = Path.GetExtension(path);
1682 AudioType type;
1683
1684 switch (ext)
1685 {
1686 case "mp3":
1687 case "MP3": type = AudioType.MPEG; break;
1688 case "ogg":
1689 case "OGG": type = AudioType.OGGVORBIS; break;
1690 case "wav":
1691 case "WAV":
1692 default: type = AudioType.WAV; break;
1693 }
1694
1695#if UNITY_ANDROID
1696 path = "file://" + path;
1697#elif UNITY_IPHONE
1698 path = "file:///" + path;
1699#endif
1700
1701 using (var req = UnityWebRequestMultimedia.GetAudioClip(path, type))
1702 {
1703 yield return req.SendWebRequest();
1704
1705#if UNITY_2020_1_OR_NEWER
1706 if (req.result == UnityWebRequest.Result.ConnectionError ||
1707 req.result == UnityWebRequest.Result.DataProcessingError ||
1708 req.result == UnityWebRequest.Result.ProtocolError)
1709 {
1710 Debug.LogError($"Couldn't load file at path: {path} \n{req.error}");
1711 onEnd?.Invoke(null);
1712 yield break;
1713 }
1714#else
1715 if (req.isHttpError || req.isNetworkError)
1716 {
1717 Debug.LogError($"Couldn't load file at path: {path} \n{req.error}");
1718 onEnd?.Invoke(null);
1719 yield break;
1720 }
1721#endif
1722 var clip = DownloadHandlerAudioClip.GetContent(req);
1723
1724 if (clip == null)
1725 {
1726 Debug.LogError("The loaded clip is null!");
1727 yield break;
1728 }
1729
1730 clip.name = Path.GetFileName(path);
1731 onEnd?.Invoke(clip);
1732 }
1733 }
1734
1740 public void CsoundReset()
1741 {
1742 csound.Reset();
1743 }
1744
1749 public void Cleanup()
1750 {
1751 csound.Cleanup();
1752 }
1753
1754 #region PRESETS
1755
1763 public static CsoundUnityPreset CreatePreset(string presetName, string csoundFileName, List<CsoundChannelController> channels)
1764 {
1765 var preset = ScriptableObject.CreateInstance<CsoundUnityPreset>();
1766 preset.name = preset.presetName = string.IsNullOrWhiteSpace(presetName) ? "CsoundUnityPreset" : presetName;
1767 preset.csoundFileName = csoundFileName;
1768 preset.channels = new List<CsoundChannelController>();
1769 foreach (var chan in channels)
1770 {
1771 var newChan = chan.Clone();
1772 preset.channels.Add(newChan);
1773 }
1774 return preset;
1775 }
1776
1788 public static CsoundUnityPreset CreatePreset(string presetName, string presetData)
1789 {
1790 var preset = ScriptableObject.CreateInstance<CsoundUnityPreset>();
1791
1792 // try and create a CsoundUnityPreset from presetData
1793 try
1794 {
1795 JsonUtility.FromJsonOverwrite(presetData, preset);
1796 }
1797 catch (ArgumentException ex)
1798 {
1799 Debug.LogError($"Couldn't set Preset {presetName}, {ex.Message}");
1800 return null;
1801 }
1802 preset.name = preset.presetName = string.IsNullOrWhiteSpace(presetName) ?
1803 string.IsNullOrWhiteSpace(preset.presetName) ?
1804 "CsoundUnityPreset" : preset.presetName : presetName;
1805
1806 return preset;
1807 }
1808
1815 public static void WritePreset(CsoundUnityPreset preset, string path)
1816 {
1817#if UNITY_EDITOR
1818 // create target directory if it doesn't exist, defaulting to "Assets"
1819 if (string.IsNullOrWhiteSpace(path) || !path.Contains("Assets"))
1820 {
1821 Debug.LogWarning("CsoundUnityPreset scriptable object cannot be created outside of the project folder, " +
1822 "defaulting to 'Assets'. Use the JSON format to save it outside of the Application.dataPath folder.");
1823 path = Application.dataPath;
1824 }
1825
1826 // convert to a path inside the project
1827 var assetsIndex = path.IndexOf("Assets");
1828
1829 if (assetsIndex < "Assets".Length)
1830 {
1831 Debug.LogError("Error, couldn't find the Assets folder!");
1832 return;
1833 }
1834
1835 path = path.Substring(assetsIndex, path.Length - assetsIndex);
1836
1837 if (!File.Exists(path))
1838 {
1839 Directory.CreateDirectory(path);
1840 }
1841
1842 var fullPath = Path.Combine(path, $"{preset.presetName}.asset");//path + $"{preset.presetName}.asset";//
1843 if (AssetDatabase.LoadAssetAtPath<CsoundUnityPreset>(fullPath) != null)
1844 {
1845 var assetLength = ".asset".Length;
1846 var basePath = $"{fullPath.Substring(0, fullPath.Length - assetLength)}";
1847 var baseName = preset.presetName;
1848 var overwriteAction = new Action(() =>
1849 {
1850 AssetDatabase.DeleteAsset(fullPath);
1851 AssetDatabase.CreateAsset(preset, fullPath);
1852 Debug.Log($"Overwriting CsoundUnityPreset at path {fullPath}");
1853 });
1854 var renameAction = new Action(() =>
1855 {
1856 var count = 0;
1857 while (AssetDatabase.LoadAssetAtPath<CsoundUnityPreset>(fullPath) != null)
1858 {
1859 preset.presetName = $"{baseName}_{count}";
1860 fullPath = $"{basePath}_{count}.asset";
1861 count++;
1862 }
1863
1864 Debug.Log($"Saving CsoundUnityPreset at path {fullPath}");
1865 AssetDatabase.CreateAsset(preset, fullPath);
1866 });
1867
1868 var message = $"CsoundUnityPreset at {fullPath} already exists, overwrite or rename?";
1869 var res = EditorUtility.DisplayDialogComplex("Overwrite?", message, "Overwrite", "Cancel", "Rename");
1870 switch (res)
1871 {
1872 case 0:
1873 overwriteAction.Invoke();
1874 break;
1875 case 1:
1876 // do nothing if cancel
1877 break;
1878 case 2:
1879 renameAction.Invoke();
1880 break;
1881 }
1882 }
1883 else
1884 {
1885 Debug.Log($"Creating new CsoundUnityPreset at {fullPath}");
1886 AssetDatabase.CreateAsset(preset, fullPath);
1887 }
1888 AssetDatabase.SaveAssets();
1889 AssetDatabase.Refresh();
1890#endif
1891 }
1892
1900 public void SavePresetAsScriptableObject(string presetName, string path = null)
1901 {
1902#if UNITY_EDITOR
1903 var preset = CreatePreset(presetName, this.csoundFileName, this.channels);
1904 WritePreset(preset, path);
1905#endif
1906 }
1907
1915 public static void SavePresetAsJSON(CsoundUnityPreset preset, string path = null, bool overwriteIfExisting = false)
1916 {
1917 var fullPath = CheckPathForExistence(path, preset.presetName, overwriteIfExisting);
1918 var presetData = JsonUtility.ToJson(preset, true);
1919 try
1920 {
1921 Debug.Log($"Saving JSON preset at {fullPath}");
1922 File.WriteAllText($"{fullPath}", presetData);
1923 }
1924 catch (IOException ex)
1925 {
1926 Debug.Log(ex.Message);
1927 }
1928#if UNITY_EDITOR
1929 AssetDatabase.Refresh();
1930#endif
1931 }
1932
1942 public static void SavePresetAsJSON(List<CsoundChannelController> channels, string csoundFileName, string presetName, string path = null, bool overwriteIfExisting = false)
1943 {
1944 var preset = ScriptableObject.CreateInstance<CsoundUnityPreset>();
1945 preset.channels = channels;
1946 presetName = string.IsNullOrWhiteSpace(presetName) ? "CsoundUnityPreset" : presetName;
1947 preset.presetName = presetName;
1948 preset.csoundFileName = csoundFileName;
1949 SavePresetAsJSON(preset, path, overwriteIfExisting);
1950 }
1951
1959 public void SavePresetAsJSON(string presetName, string path = null, bool overwriteIfExisting = false)
1960 {
1961 var preset = ScriptableObject.CreateInstance<CsoundUnityPreset>();
1962 preset.channels = this.channels;
1963 presetName = string.IsNullOrWhiteSpace(presetName) ? "CsoundUnityPreset" : presetName;
1964 preset.presetName = presetName;
1965 preset.csoundFileName = this.csoundFileName;
1966 SavePresetAsJSON(preset, path, overwriteIfExisting);
1967 }
1968
1974 public void SaveGlobalPreset(string presetName, string path = null, bool overwriteIfExisting = false)
1975 {
1976 var presetData = JsonUtility.ToJson(this, true);
1977 try
1978 {
1979 var name = $"{presetName} {GLOBAL_TAG}";
1980 var fullPath = CheckPathForExistence(path, name, overwriteIfExisting);
1981 Debug.Log($"Saving global preset at {fullPath}");
1982 File.WriteAllText(fullPath, presetData);
1983 }
1984 catch (IOException ex)
1985 {
1986 Debug.Log(ex.Message);
1987 }
1988#if UNITY_EDITOR
1989 AssetDatabase.Refresh();
1990#endif
1991 }
1992
1998 public void ConvertPresetToScriptableObject(string path, string destination)
1999 {
2000#if UNITY_EDITOR
2001 //Debug.Log($"ConvertPresetToScriptableObject at path: {path}, to dest: {destination}");
2002 LoadPreset(path, (preset) =>
2003 {
2004 //Debug.Log($"Loaded Preset Name: {preset.presetName}");
2005 WritePreset(preset, destination);
2006 });
2007#endif
2008 }
2009
2020 public CsoundUnityPreset SetPreset(string presetName, string presetData)
2021 {
2022 var preset = CreatePreset(presetName, presetData);
2023 SetPreset(preset);
2024 return preset;
2025 }
2026
2038 public CsoundUnityPreset SetPreset(string presetData)
2039 {
2040 return SetPreset("", presetData);
2041 }
2042
2049 public void SetPreset(CsoundUnityPreset preset)
2050 {
2051 if (this.csoundFileName != preset.csoundFileName)
2052 {
2053 Debug.LogError($"Couldn't set preset {preset.presetName} to this CsoundUnity instance {this.name}, " +
2054 $"this instance uses csd: {this.csoundFileName}, the preset was saved with csd: {preset.csoundFileName} instead");
2055 return;
2056 }
2057 if (preset == null)
2058 {
2059 Debug.LogError("Couldn't load a null CsoundUnityPreset!");
2060 }
2061
2062 _currentPreset = preset.presetName;
2063 SetChannels(preset.channels, true);
2064 }
2065
2077 public CsoundUnity SetGlobalPreset(string presetName, string presetData)
2078 {
2079 JsonUtility.FromJsonOverwrite(presetData, this);
2080 // update the serialized channels
2081 SetChannels(this.channels, true);
2082 var current = string.IsNullOrWhiteSpace(presetName) ? this._currentPreset : presetName;
2083 _currentPreset = $"{current} {GLOBAL_TAG}";
2084 return this;
2085 }
2086
2105 public void LoadPreset(string path, Action<CsoundUnityPreset> onPresetLoaded = null)
2106 {
2107 var presetName = Path.ChangeExtension(Path.GetFileName(path), null);
2108
2109#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
2110 StartCoroutine(LoadingData(path, (d) =>
2111 {
2112 if (d == null)
2113 {
2114 onPresetLoaded?.Invoke(null);
2115 }
2116 var preset = CreatePreset(presetName, d);
2117 onPresetLoaded?.Invoke(preset);
2118 }));
2119#else
2120 if (!File.Exists(path))
2121 {
2122 Debug.LogError($"Preset JSON not found at path {path}");
2123 return;
2124 }
2125 var data = File.ReadAllText(path);
2126 var preset = CreatePreset(presetName, data);
2127 if (preset == null)
2128 {
2129 Debug.LogError("Couldn't create preset from path: {path}");
2130 onPresetLoaded?.Invoke(null);
2131 return;
2132 }
2133 onPresetLoaded?.Invoke(preset);
2134#endif
2135 }
2136
2145 public void LoadGlobalPreset(string path)
2146 {
2147 var presetName = Path.GetFileName(path);
2148
2149#if UNITY_ANDROID || UNITY_IOS
2150 StartCoroutine(LoadingData(path, (d) =>
2151 {
2152 SetGlobalPreset(presetName, d);
2153 }));
2154#else
2155 if (!File.Exists(path))
2156 {
2157 Debug.LogError($"Global Preset JSON not found at path {path}");
2158 return;
2159 }
2160 var data = File.ReadAllText(path);
2161 SetGlobalPreset(presetName, data);
2162#endif
2163 }
2164
2171 public static List<CsoundUnityPreset> ParseSnap(string csdPath, string snapPath)
2172 {
2173 //Debug.Log($"Parse snap: csdPath: {csdPath}, snapPath: {snapPath}");
2174
2175 var snap = File.ReadAllText(snapPath);
2176 var snapStart = snap.IndexOf("{");
2177 var snapEnd = snap.LastIndexOf("}");
2178 var presets = snap.Substring(snapStart + 1, snapEnd - snapStart - 2);
2179 var csdName = Path.GetFileName(csdPath);
2180
2181 //Debug.Log($"presets: {presets}");
2182 var parsedPresets = ParsePresets(csdName, presets);
2183 var originalChannels = ParseCsdFile(csdPath);
2184 if (originalChannels == null || originalChannels.Count == 0)
2185 {
2186 if (originalChannels == null || originalChannels.Count == 0)
2187 {
2188 Debug.LogWarning($"Couldn't fix preset channels for snap {snapPath}, csd path: {csdPath}, preset channels will not be visible on Editor, " +
2189 $"but you should still be able to use them. Be aware that Comboboxes will be broken. " +
2190 $"Please ensure that a '.csd' file with the same name of the '.snaps' file is present at the same location.");
2191 return parsedPresets;
2192 }
2193 }
2194 foreach (var preset in parsedPresets)
2195 {
2196 FixPresetChannels(originalChannels, preset.channels);
2197 }
2198 Debug.Log($"originalChannels: {originalChannels.Count}");
2199 return parsedPresets;
2200 }
2201
2202 private static List<CsoundUnityPreset> ParsePresets(string snapName, string presets)
2203 {
2204 var parsedPresets = new List<CsoundUnityPreset>();
2205 var splitPresets = presets.Split(new string[] { "}," }, StringSplitOptions.None);
2206
2207 foreach (var preset in splitPresets)
2208 {
2209 //Debug.Log($"--> preset: {preset}");
2210 parsedPresets.Add(ParsePreset(snapName, preset));
2211 }
2212
2213 //foreach (var preset in parsedPresets)
2214 //{
2215 // Debug.Log($"<color=green>Preset: {preset.presetName}, csd: {preset.csoundFileName}, num channels: {preset.channels.Count}</color>");
2216 // foreach (var channel in preset.channels)
2217 // {
2218 // Debug.Log($"<color=orange>Channel: {channel.channel} = {channel.value}</color>");
2219 // }
2220 //}
2221 return parsedPresets;
2222 }
2223
2224 private static CsoundUnityPreset ParsePreset(string snapName, string preset)
2225 {
2226 var presetNameStart = preset.IndexOf("\"");
2227 var subPreset = preset.Substring(presetNameStart + 1, preset.Length - presetNameStart - 1);
2228 //Debug.Log($"SubPreset: {subPreset}");
2229 var presetNameEnd = subPreset.IndexOf("\"");
2230 var presetName = subPreset.Substring(0, presetNameEnd);
2231 //Debug.Log($"--> presetName: {presetName}");
2232 var presetContentStart = preset.IndexOf("{");
2233 var presetContent = preset.Substring(presetContentStart + 1, preset.Length - presetContentStart - 1);
2234 //Debug.Log($"presetContent: {presetContent}");
2235 var splitPresetContent = presetContent.Split(new string[] { "," }, StringSplitOptions.None);
2236 var presetChannels = new List<CsoundChannelController>();
2237 foreach (var chan in splitPresetContent)
2238 {
2239 //Debug.Log($"chan: {chan}");
2240 presetChannels.Add(ParseChannel(chan).Clone());
2241 }
2242
2243 return CreatePreset(presetName, snapName, presetChannels);
2244 }
2245
2246 private static CsoundChannelController ParseChannel(string chan)
2247 {
2248 var split = chan.Split(new string[] { ":" }, StringSplitOptions.None);
2249 var chanName = split[0];//.Replace('"', new char());
2250 var chanValue = split[1];
2251 //Debug.Log($"Channel Name: {chanName}, Value: {chanValue}");
2252 var cleanChanName = chanName.Replace("\"", "").Trim(); //Trim(new char[] { '"' });
2253 float.TryParse(chanValue, out float chanValueFloat);
2254 //Debug.Log($"Clean chan name: {cleanChanName}, float value: {chanValueFloat}");
2255 var cc = new CsoundChannelController()
2256 {
2257 channel = cleanChanName,
2258 value = chanValueFloat
2259 };
2260 //Debug.Log($"Created channel controller: {cc.channel}, value: {cc.value}");
2261 return cc;
2262 }
2263
2264 private static void FixPresetChannels(List<CsoundChannelController> originalChannels, List<CsoundChannelController> channelsToFix)
2265 {
2266 if (originalChannels == null || originalChannels.Count == 0)
2267 {
2268 Debug.LogError("Couldn't fix preset channels, aborting");
2269 return;
2270 }
2271
2272 foreach (var chanToFix in channelsToFix)
2273 {
2274 foreach (var chan in originalChannels)
2275 {
2276 if (chan.channel == chanToFix.channel)
2277 {
2278 // channel and value come from the Cabbage snap
2279 // but not all the other fields
2280 // set all the missing fields
2281 chanToFix.caption = chan.caption;
2282 chanToFix.increment = chan.increment;
2283 chanToFix.max = chan.max;
2284 chanToFix.min = chan.min;
2285 chanToFix.options = chan.options;
2286 chanToFix.skew = chan.skew;
2287 chanToFix.text = chan.text;
2288 chanToFix.type = chan.type;
2289
2290 // also fix the combobox index?
2291 if (chanToFix.type.Equals("combobox"))
2292 {
2293 chanToFix.value -= 1;
2294 }
2295 }
2296 }
2297 }
2298 }
2299
2300 static IEnumerator LoadingData(string path, Action<string> onDataLoaded)
2301 {
2302 Debug.Log($"Loading JSON data from path: {path}");
2303 using (var request = UnityWebRequest.Get(path))
2304 {
2305 request.downloadHandler = new DownloadHandlerBuffer();
2306 yield return request.SendWebRequest();
2307 if (request.isNetworkError || request.isHttpError)
2308 {
2309 Debug.Log($"Couldn't load data at path: {path}: {request.error}");
2310 onDataLoaded?.Invoke(null);
2311 yield break;
2312 }
2313 var data = request.downloadHandler.text;
2314 onDataLoaded?.Invoke(data);
2315 }
2316 }
2317
2318 private static string CheckPathForExistence(string path, string presetName, bool overwriteIfExisting)
2319 {
2320 path = string.IsNullOrWhiteSpace(path) ?
2321 Application.persistentDataPath
2322 : path;
2323 if (!char.IsSeparator(path[path.Length - 1]))
2324 {
2325 path = $"{path}/";
2326 }
2327
2328 if (!Directory.Exists(path))
2329 {
2330 try
2331 {
2332 Directory.CreateDirectory(path);
2333 }
2334 catch (IOException ex)
2335 {
2336 Debug.LogError($"Couldn't create folder at: {path}, defaulting to {Application.persistentDataPath} {ex.Message}");
2337 path = Application.persistentDataPath;
2338 }
2339 }
2340
2341 var fullPath = Path.Combine(path, presetName + ".json");
2342
2343 var count = 0;
2344 while (File.Exists(fullPath) && !overwriteIfExisting)
2345 {
2346 fullPath = Path.Combine(path, $"{presetName}_{count++}.json");
2347 }
2348 return fullPath;
2349 }
2350
2351 #endregion PRESETS
2352
2353 #endregion UTILITIES
2354
2355 #endregion PUBLIC_METHODS
2356
2357
2358 #region ENUMS
2359
2363 public enum EnvType
2364 {
2369 SFDIR,
2370
2377 SSDIR,
2378
2383 SADIR,
2384
2390 SFOUTYP,
2391
2395 INCDIR,
2396
2400 OPCODE6DIR,
2401
2405 OPCODE6DIR64,
2406
2410 SNAPDIR,
2411
2417 CSOUNDRC,
2424 CSSTRNGS,
2425
2429 CS_LANG,
2430
2435 RAWWAVE_PATH,
2436
2444 CSNOSTOP,
2445
2451 MFDIR,
2452
2457 CS_OMIT_LIBS
2458 }
2459
2466 public enum SamplesOrigin { Resources, StreamingAssets, Absolute } // TODO Add PersistentDataPath and URL
2467
2468 #endregion ENUMS
2469
2470
2471 #region PRIVATE_METHODS
2472
2473 void OnAudioFilterRead(float[] data, int channels)
2474 {
2475 if (csound != null)
2476 {
2477 ProcessBlock(data, channels);
2478 }
2479 }
2480
2486 private void ProcessBlock(float[] samples, int numChannels)
2487 {
2488 if (compiledOk && initialized && !_quitting)
2489 {
2490 for (int i = 0; i < samples.Length; i += numChannels, ksmpsIndex++)
2491 {
2492 for (uint channel = 0; channel < numChannels; channel++)
2493 {
2494 // necessary to avoid calling csound functions when quitting while reading this block of samples
2495 // always remember OnAudioFilterRead runs on a different thread
2496 if (_quitting) return;
2497
2498 if (mute == true)
2499 samples[i + channel] = 0.0f;
2500 else
2501 {
2502 if ((ksmpsIndex >= GetKsmps()) && (GetKsmps() > 0))
2503 {
2504 var res = PerformKsmps();
2505 performanceFinished = res == 1;
2506 ksmpsIndex = 0;
2507
2508 foreach (var chanName in availableAudioChannels)
2509 {
2510 if (!namedAudioChannelTempBufferDict.ContainsKey(chanName)) continue;
2511 namedAudioChannelTempBufferDict[chanName] = GetAudioChannel(chanName);
2512 }
2513 }
2514
2515 if (processClipAudio)
2516 {
2517 SetInputSample((int)ksmpsIndex, (int)channel, samples[i + channel] * zerdbfs);
2518 }
2519
2520 //if csound nChnls are more than the current channel, set the last csound channel available on the sample (assumes GetNchnls above 0)
2521 var outputSampleChannel = channel < GetNchnls() ? channel : GetNchnls() - 1;
2522 var output = (float)GetOutputSample((int)ksmpsIndex, (int)outputSampleChannel) / zerdbfs;
2523 // multiply Csound output by the sample value to maintain spatialization set by Unity.
2524 // don't multiply if reading from a clip: this should maintain the spatialization of the clip anyway
2525 samples[i + channel] = processClipAudio ? output : samples[i + channel] * output;
2526
2527 if (loudVolumeWarning && (samples[i + channel] > loudWarningThreshold))
2528 {
2529 samples[i + channel] = 0.0f;
2530 Debug.LogWarning("Volume is too high! Clearing output");
2531 }
2532 }
2533 }
2534
2535 // update the audioChannels just when this instance is not muted
2536 if (!mute)
2537 foreach (var chanName in availableAudioChannels)
2538 {
2539 if (!namedAudioChannelDataDict.ContainsKey(chanName) || !namedAudioChannelTempBufferDict.ContainsKey(chanName)) continue;
2540 namedAudioChannelDataDict[chanName][i / numChannels] = namedAudioChannelTempBufferDict[chanName][ksmpsIndex];
2541 }
2542 }
2543 }
2544 }
2545
2550 void LogCsoundMessages()
2551 {
2552 //print Csound message to Unity console....
2553 for (int i = 0; i < csound.GetCsoundMessageCount(); i++)
2554 print(csound.GetCsoundMessage());
2555 }
2556
2562 IEnumerator Logging(float interval)
2563 {
2564 while (true)
2565 {
2566 while (this.logCsoundOutput)
2567 {
2568 for (int i = 0; i < csound.GetCsoundMessageCount(); i++)
2569 {
2570 if (this.logCsoundOutput) // exiting when csound messages are very high in number
2571 {
2572 print(csound.GetCsoundMessage());
2573 yield return null; //avoids Unity stuck on performance end
2574 }
2575 }
2576 yield return new WaitForSeconds(interval);
2577 }
2578 yield return null; //wait one frame
2579 }
2580 }
2581
2582
2586 private void ResetFields()
2587 {
2588#if UNITY_EDITOR
2589 this._csoundAsset = null;
2590#endif
2591
2592 this._csoundFileName = null;
2593 this._csoundString = null;
2594 this._csoundFileGUID = string.Empty;
2595
2596 this._channels.Clear();
2597 this._availableAudioChannels.Clear();
2598
2599 this.namedAudioChannelDataDict.Clear();
2600 this.namedAudioChannelTempBufferDict.Clear();
2601 }
2602
2603 private bool _quitting = false;
2607 void OnApplicationQuit()
2608 {
2609 _quitting = true;
2610 if (LoggingCoroutine != null)
2611 StopCoroutine(LoggingCoroutine);
2612
2613 if (csound != null)
2614 {
2615 csound.OnApplicationQuit();
2616 }
2617 }
2618
2619 #endregion PRIVATE_METHODS
2620}
SupportedPlatform
Definition: CsoundUnity.cs:254
EnvironmentPathOrigin
The base folder where to set the Environment Variables
Definition: CsoundUnity.cs:260
Utility class for controller and channels
Definition: CsoundUnity.cs:51
void SetRange(float uMin, float uMax, float uValue=0f, float uSkew=1f, float uIncrement=0.01f)
Definition: CsoundUnity.cs:63
CsoundChannelController Clone()
Definition: CsoundUnity.cs:72
Defines a class to hold out and in types, and flags
int CompileOrc(string orchStr)
void SetTable(int table, int index, MYFLT value)
Sets the value of a slot in a function table. The table number and index are assumed to be valid.
IDictionary< string, int > GetNamedGens()
Returns a Dictionary keyed by the names of all named table generators. Each name is paired with its i...
uint GetNchnls()
Get number of input channels
void SetSpinSample(int frame, int channel, MYFLT sample)
Set a sample from Csound's audio output buffer
IDictionary< string, IList< OpcodeArgumentTypes > > GetOpcodeList()
Returns a sorted Dictionary keyed by all opcodes which are active in the current instance of csound....
void GetNamedGEN(int num, out string name, int len)
Gets the GEN name from a number num, if this is a named GEN The final parameter is the max len of the...
MYFLT[] GetAudioChannel(string name)
int GetTableArgs(out MYFLT[] args, int index)
Stores the arguments used to generate function table 'tableNum' in args, and returns the number of ar...
void ClearSpin()
Clears the input buffer (spin).
uint GetNchnlsInput()
Get number of input channels
MYFLT GetTable(int table, int index)
Returns the value of a slot in a function table. The table number and index are assumed to be valid.
void TableCopyIn(int table, MYFLT[] source)
Copy the contents of an array source into a given function table The table number is assumed to be va...
void SendScoreEvent(string scoreEvent)
void SetParams(CSOUND_PARAMS parms)
Transfers the contents of the provided raw CSOUND_PARAMS object into csound's internal data structues...
void TableCopyOutAsync(int table, out MYFLT[] dest)
Asynchronous version of tableCopyOut()
void SetStringChannel(string channel, string value)
void AddSpinSample(int frame, int channel, MYFLT sample)
CSOUND_PARAMS GetParams()
Fills in a provided raw CSOUND_PARAMS object with csounds current parameter settings....
string GetEnv(string key)
Gets a string value from csound's environment values. Meaningful values include the contents of Windo...
int LoadPlugins(string dir)
IDictionary< string, ChannelInfo > GetChannelList()
Provides a dictionary of all currently defined channels resulting from compilation of an orchestra co...
MYFLT GetSpoutSample(int frame, int channel)
Get a sample from Csound's audio output buffer
MYFLT GetChannel(string channel)
Get a a control channel
void TableCopyInAsync(int table, MYFLT[] source)
Asynchronous version of csoundTableCopyIn()
int SetGlobalEnv(string name, string value)
Set the global value of environment variable 'name' to 'value', or delete variable if 'value' is NULL...
int IsNamedGEN(int num)
Checks if a given GEN number num is a named GEN if so, it returns the string length (excluding termin...
void CsoundSetScoreOffsetSeconds(MYFLT value)
void TableCopyOut(int table, out MYFLT[] dest)
Copy the contents of a function table into a supplied array dest The table number is assumed to be va...
void SetChannel(string channel, MYFLT value)
int TableLength(int table)
Returns the length of a function table (not including the guard point), or -1 if the table does not e...
MYFLT[] GetSpout()
Returns the Csound audio output working buffer (spout) as a MYFLT array. Enables external software to...
MYFLT[] GetSpin()
Returns the Csound audio input working buffer (spin) as a MYFLT array. Enables external software to w...
Csound Unity Class
Definition: CsoundUnity.cs:271
int CreateTable(int tableNumber, MYFLT[] samples)
Creates a table with the supplied samples. Can be called during performance.
string csoundFileName
The file CsoundUnity will try to load. You can only load one file with each instance of CsoundUnity,...
Definition: CsoundUnity.cs:294
CsoundInitialized OnCsoundInitialized
An event that will be executed when Csound is initialized
Definition: CsoundUnity.cs:367
int CreateTableInstrument(int tableNumber, int tableLength)
Creates an empty table, to be filled with samples later. Please note that trying to read the samples ...
readonly Dictionary< string, MYFLT[]> namedAudioChannelDataDict
public named audio Channels shown in CsoundUnityChild inspector
Definition: CsoundUnity.cs:353
void CopyTableOutAsync(int table, out MYFLT[] dest)
Asynchronous version of CopyTableOut.
long GetCurrentTimeSamples()
Returns the current performance time in samples
uint GetNchnls()
Get the number of output channels
MYFLT[] GetSpin()
Get Csound's audio input buffer
Definition: CsoundUnity.cs:973
string csoundString
a string to hold all the csoundFile content
Definition: CsoundUnity.cs:299
void LoadGlobalPreset(string path)
Load a global preset on this CsoundUnity instance from a JSON file found at path. The JSON file shoul...
List< CsoundChannelController > channels
list to hold channel data
Definition: CsoundUnity.cs:343
void SetStringChannel(string channel, string val)
Sets a string channel in Csound. Used in connection with a chnget opcode in your Csound instrument.
static float[] GetFloatSamples(string source, int channelNumber=1, bool writeChannelData=false)
Same as GetSamples but it will return a float array.
int GetTableArgs(out MYFLT[] args, int index)
Stores the arguments used to generate function table 'tableNum' in args, and returns the number of ar...
void ConvertPresetToScriptableObject(string path, string destination)
Convert a JSON preset into a Scriptable Object preset to be written at the specified path....
static MYFLT[] GetSamples(string source, int channelNumber=1, bool writeChannelData=false)
Get Samples from a "Resources" path. This will return an interleaved array of samples,...
CsoundUnityPreset SetPreset(string presetData)
Set a CsoundUnityPreset to this CsoundUnity instance using presetData.
CsoundUnityPreset SetPreset(string presetName, string presetData)
Set a CsoundUnityPreset to this CsoundUnity instance using a presetName and presetData....
static MYFLT[] ConvertToMYFLT(float[] samples)
Utility method to create an array of MYFLTs from an array of floats
int PerformKsmps()
Process a ksmps-sized block of samples
Definition: CsoundUnity.cs:713
void SetChannel(string channel, MYFLT val)
Sets a Csound channel. Used in connection with a chnget opcode in your Csound instrument.
Definition: CsoundUnity.cs:995
CsoundUnity SetGlobalPreset(string presetName, string presetData)
Set a global preset to this CsoundUnity instance using a presetName and presetData.
void SetCsd(string guid)
Sets the csd file
Definition: CsoundUnity.cs:591
static List< CsoundChannelController > ParseCsdFile(string filename)
Parse the csd file
Definition: CsoundUnity.cs:769
MYFLT[] GetSpout()
Get Csound's audio output buffer
Definition: CsoundUnity.cs:982
static MYFLT[] GetSamples(AudioClip audioClip)
Get samples from an AudioClip as a MYFLT array.
bool loudVolumeWarning
If true it will print warnings in the console when the output volume is too high, and mute all the sa...
Definition: CsoundUnity.cs:332
static CsoundUnityPreset CreatePreset(string presetName, string csoundFileName, List< CsoundChannelController > channels)
Create a CsoundUnityPreset from a presetName, csoundFileName and a list of CsoundChannelControllers
uint GetKsmps()
Get the number of audio sample frames per control sample.
Definition: CsoundUnity.cs:722
uint GetNchnlsInputs()
Get the number of input channels
static float RemapFrom0to1(float value, float from, float to, float skew=1f)
Remap a normalized (0-1) value to a value in another range, specifying its "from" and "to" values,...
int GetAPIVersion()
Returns the Csound API version number times 100 (1.00 = 100).
Definition: CsoundUnity.cs:559
SamplesOrigin
Where the samples to load come from:
static MYFLT[] GetMonoSamples(string source, int channelNumber)
Get an array of MYFLTs from the AudioClip source from the Resources folder. No information about the ...
void SetPreset(CsoundUnityPreset preset)
Set a CsoundUnityPreset to this CsoundUnity instance.
bool processClipAudio
If true Csound uses as an input the AudioClip attached to this AudioSource If false,...
Definition: CsoundUnity.cs:326
static float RemapTo0to1(float value, float from, float to, float skew=1f)
Remap a value to a normalized (0-1) value specifying its expected "from" and "to" values,...
static void SavePresetAsJSON(List< CsoundChannelController > channels, string csoundFileName, string presetName, string path=null, bool overwriteIfExisting=false)
Save a preset as JSON from a list of CsoundChannelController, specifying the related CsoundFileName a...
void SetTable(int table, int index, MYFLT value)
Sets the value of a slot in a function table. The table number and index are assumed to be valid.
void SendScoreEvent(string scoreEvent)
Send a score event to Csound in the form of "i1 0 10 ....
Definition: CsoundUnity.cs:664
void AddInputSample(int frame, int channel, MYFLT sample)
Adds the indicated sample into the audio input working buffer (spin); this only ever makes sense befo...
Definition: CsoundUnity.cs:941
CsoundChannelController GetChannelController(string channel)
Get a serialized CsoundChannelController
MYFLT Get0dbfs()
Get 0 dbfs
int GetTable(out MYFLT[] tableValues, int numTable)
Stores values to function table 'numTable' in tableValues, and returns the table length (not includin...
void SavePresetAsJSON(string presetName, string path=null, bool overwriteIfExisting=false)
Save a preset as JSON using CsoundChannelControllers and CsoundFileName from this CsoundUnity instanc...
static float[] GetStereoFloatSamples(string source)
Get an array of floats from the AudioClip source from the Resources folder. The first index in the re...
void ClearSpin()
Clears the input buffer (spin).
Definition: CsoundUnity.cs:949
void LoadPreset(string path, Action< CsoundUnityPreset > onPresetLoaded=null)
Loads a preset from a JSON file. The JSON file should represent a CsoundUnityPreset.
MYFLT GetSr()
Get the current sample rate
Definition: CsoundUnity.cs:695
float loudWarningThreshold
The volume threshold at which a warning is output to the console, and audio output is filtered
Definition: CsoundUnity.cs:338
List< EnvironmentSettings > environmentSettings
The list of the Environment Settings that will be set on start, using csoundSetGlobalEnv....
Definition: CsoundUnity.cs:382
IDictionary< string, IList< CsoundUnityBridge.OpcodeArgumentTypes > > GetOpcodeList()
Get the Opcode List, blocking
void CopyTableInAsync(int table, MYFLT[] source)
Asynchronous version of CopyTableIn
string csoundFileGUID
the unique guid of the csd file
Definition: CsoundUnity.cs:287
bool logCsoundOutput
If true, all Csound output messages will be sent to the Unity output console. Note that this can slow...
Definition: CsoundUnity.cs:315
int SetGlobalEnv(string name, string value)
Set the global value of environment variable 'name' to 'value', or delete variable if 'value' is NULL...
void RewindScore()
Rewinds a compiled Csound score to the time specified with SetScoreOffsetSeconds().
Definition: CsoundUnity.cs:673
bool mute
If true no audio is sent to output
Definition: CsoundUnity.cs:320
void GetNamedGEN(int num, out string name, int len)
Gets the GEN name from a number num, if this is a named GEN The final parameter is the max len of the...
void CopyFloatTableIn(int table, float[] source)
Same as CopyTableIn but passing a float array.
static float Remap(float value, float from1, float to1, float from2, float to2, bool clamp=false)
Linear remap floats within one range to another
void SaveGlobalPreset(string presetName, string path=null, bool overwriteIfExisting=false)
Save a serialized copy of this CsoundUnity instance. Similar behaviour as saving a Unity Preset from ...
int GetTableLength(int table)
Returns the length of a function table (not including the guard point), or -1 if the table does not e...
static float[] GetMonoFloatSamples(string source, int channelNumber)
Get an array of floats from the AudioClip source from the Resources folder. No information about the ...
string CurrentPreset
The current preset name. If empty, no preset has been set.
Definition: CsoundUnity.cs:387
const string packageVersion
The version of this package
Definition: CsoundUnity.cs:282
void SetChannel(CsoundChannelController channelController)
Sets a Csound channel. Useful for setting presets at runtime. Used in connection with a chnget opcode...
static void SavePresetAsJSON(CsoundUnityPreset preset, string path=null, bool overwriteIfExisting=false)
Save the specified CsoundUnityPreset as JSON, at the specified path. If a file exists at the specifie...
MYFLT GetOutputSample(int frame, int channel)
Get a sample from Csound's audio output buffer
Definition: CsoundUnity.cs:964
void CopyTableOut(int table, out MYFLT[] dest)
Copy the contents of a function table into a supplied array dest The table number is assumed to be va...
void SavePresetAsScriptableObject(string presetName, string path=null)
Save a CsoundUnityPreset of this CsoundUnity instance at the specified path, using the specified pres...
static void WritePreset(CsoundUnityPreset preset, string path)
Write a CsoundUnityPreset at the specified path inside the Assets folder. You can pass a full path,...
int LoadPlugins(string dir)
Loads all plugins from a given directory
Definition: CsoundUnity.cs:569
EnvType
The enum representing the Csound Environment Variables
static CsoundUnityPreset CreatePreset(string presetName, string presetData)
Create a CsoundUnityPreset from a presetName and presetData.
void SetInputSample(int frame, int channel, MYFLT sample)
Set a sample in Csound's input buffer
Definition: CsoundUnity.cs:927
delegate void CsoundInitialized()
The delegate of the event OnCsoundInitialized
static List< CsoundUnityPreset > ParseSnap(string csdPath, string snapPath)
Parse a Cabbage Snap and return a list of CsoundUnityPresets.
IDictionary< string, CsoundUnityBridge.ChannelInfo > GetChannelList()
Blocking method to get a list of the channels from Csound, not from the serialized list of this insta...
MYFLT GetTableSample(int tableNumber, int index)
Retrieves a single sample from a Csound function table.
string csoundScore
the score to send via editor
Definition: CsoundUnity.cs:373
void Cleanup()
Prints information about the end of a performance, and closes audio and MIDI devices....
bool PerformanceFinished
Definition: CsoundUnity.cs:369
int IsNamedGEN(int num)
Checks if a given GEN number num is a named GEN if so, it returns the string length (excluding termin...
bool CompiledWithoutError()
Returns true if the csd file was compiled without errors.
Definition: CsoundUnity.cs:578
void SetChannels(List< CsoundChannelController > channelControllers, bool excludeButtons=true)
Sets a list of Csound channels.
void SetParams(CsoundUnityBridge.CSOUND_PARAMS parms)
Transfers the contents of the provided raw CSOUND_PARAMS object into csound's internal data structues...
void CsoundReset()
Resets all internal memory and state in preparation for a new performance. Enables external software ...
MYFLT GetChannel(string channel)
Gets a Csound channel. Used in connection with a chnset opcode in your Csound instrument.
List< string > availableAudioChannels
list to hold available audioChannels names
Definition: CsoundUnity.cs:348
int CompileOrc(string orcStr)
Parse, and compile the given orchestra from an ASCII string, also evaluating any global space code (i...
Definition: CsoundUnity.cs:655
bool IsInitialized
Is Csound initialized?
Definition: CsoundUnity.cs:358
static List< string > ParseCsdFileForAudioChannels(string filename)
Parse the csd and returns available audio channels (set in csd via:
Definition: CsoundUnity.cs:736
string GetEnv(EnvType envType)
Get Environment path.
void CopyTableIn(int table, MYFLT[] source)
Copy the contents of a supplied array into a function table The table number is assumed to be valid,...
const string packageName
The name of this package
Definition: CsoundUnity.cs:277
IDictionary< string, int > GetNamedGens()
Returns a Dictionary keyed by the names of all named table generators. Each name is paired with its i...
int GetVersion()
Returns the Csound version number times 1000 (5.00.0 = 5000).
Definition: CsoundUnity.cs:550
static IEnumerator GetSamples(string source, SamplesOrigin origin, Action< MYFLT[]> onSamplesLoaded)
Async version of GetSamples
MYFLT GetKr()
Get the current control rate
Definition: CsoundUnity.cs:704
static MYFLT[] GetStereoSamples(string source)
Get an array of MYFLTs in from the AudioClip source from the Resources folder. The first index in the...
int CreateFloatTable(int tableNumber, float[] samples)
Creates a table with the supplied float samples. Can be called during performance.
void SetScoreOffsetSeconds(MYFLT value)
Csound score events prior to the specified time are not performed, and performance begins immediately...
Definition: CsoundUnity.cs:686
MYFLT[] GetAudioChannel(string channel)
Gets a Csound Audio channel. Used in connection with a chnset opcode in your Csound instrument.
static float[] ConvertToFloat(MYFLT[] samples)
Utility method to create an array of floats from an array of MYFLTs
CsoundUnityBridge.CSOUND_PARAMS GetParams()
Fills in a provided raw CSOUND_PARAMS object with csounds current parameter settings....
List< CsoundChannelController > channels
This class describes a setting that is meant to be used to set Csound's Global Environment Variables
Definition: CsoundUnity.cs:88
string GetPath(bool runtime=false)
Set the runtime bool true on Editor for debug purposes only, let Unity detect the correct path with A...
Definition: CsoundUnity.cs:101
SupportedPlatform platform
Definition: CsoundUnity.cs:89
CsoundUnity.EnvType type
Definition: CsoundUnity.cs:90
EnvironmentPathOrigin baseFolder
Definition: CsoundUnity.cs:91
string GetPathDescriptor(bool runtime)
Definition: CsoundUnity.cs:247
string GetTypeString()
Definition: CsoundUnity.cs:237
string GetPlatformString()
Definition: CsoundUnity.cs:242