/// <summary> /// Start a generator. /// </summary> /// <param name="gen">The </param> /// <param name="samples">The number of samples for the PCM buffer.</param> /// <param name="samplesPerSec">Samples per second for the PCM stream.</param> /// <returns></returns> public int StartGenerator(GenBase gen, float velocity, int samples, int samplesPerSec) { AudioSource source = null; if (this.audioSources.Count > 0) { int lastIdx = this.audioSources.Count - 1; source = this.audioSources[lastIdx]; this.audioSources.RemoveAt(lastIdx); } if (source == null) { source = this.sourceHost.AddComponent <AudioSource>(); } int retId = this.ctr; ++this.ctr; source.volume = this.masterVol * velocity; // Wrap meter analysis around it if needed. // Users of the meter "just have to know" that the meter results // are put into MeterValue.DefaultMeter if (this.metered == true) { GenMeter genMeter = new GenMeter(gen); gen = genMeter; meterRecords.Add(genMeter, new MeterRecord(genMeter, source)); } PlayingNote pn = new PlayingNote(); pn.id = retId; pn.velocity = velocity; pn.generator = gen; pn.clip = AudioClip.Create( "StreamedKeyNote", samples, 1, samplesPerSec, #if UNITY_WEBGL && !UNITY_EDITOR false, #else true, #endif pn.generator.ReaderCallback); pn.source = source; pn.source.loop = true; pn.source.clip = pn.clip; pn.source.Play(); this.activeNotes.Add(retId, pn); return(retId); }
/// <summary> /// Plays the note using the current <see cref="IPlayer"/> for <see cref="Duration"/>ms /// </summary> public void PlayNote() { if (DesiredOctave > Frequencies.Count() - 1) { var error = new ArgumentException($"{DesiredOctave} is too high of an Octave to play {Key}", nameof(DesiredOctave)); Error?.Invoke(this, error); } else { try { string[] desiredChord = null; switch (ChordType) { case ChordType.Note: desiredChord = new string[] { Key }; break; case ChordType.Power: desiredChord = PowerChord; break; case ChordType.MinorThird: desiredChord = MinorChord3; break; case ChordType.MajorThird: desiredChord = MajorChord3; break; case ChordType.MinorSeventh: desiredChord = MinorChord7; break; case ChordType.MajorSeventh: desiredChord = MajorChord7; break; } PlayingNote?.Invoke(this, new EventArgs()); var musicNotes = desiredChord.Select(sn => MusicNote.Create(sn)); var frequencies = musicNotes.Select(mn => new FrequencyDuration(mn.Key, mn.DesiredOctave, mn.Frequencies[DesiredOctave], Duration)); NotePlayer?.Play(frequencies, Instrument); } catch (Exception ex) { Error?.Invoke(this, ex); } } }
/// <summary> /// Manages if any released notes are finished being released. /// </summary> /// <returns>The number of notes finished being released.</returns> public int CheckFinishedRelease() { int finished = 0; for (int i = this.releasingNotes.Count - 1; i >= 0; --i) { PlayingNote pn = this.releasingNotes[i]; PxPre.Phonics.PlayState psfin = pn.generator.Finished(); if (psfin != PlayState.Playing) { pn.source.Stop(); pn.generator.DeconstructHierarchy(); this.audioSources.Add(pn.source); this.releasingNotes.RemoveAt(i); this.meterRecords.Remove(pn.generator); ++finished; } } return(finished); }
/// <summary> /// Deconstructs the resources used for playing a note. /// /// The resources will be absorbed back into the manager. /// </summary> /// <param name="pn">The note information to deconstruct.</param> private void StopPlayingNote(PlayingNote pn) { pn.source.Stop(); pn.generator.DeconstructHierarchy(); this.audioSources.Add(pn.source); }