/// <summary> /// Passed a note/chord for lead, and note for melody. This chooses a sampler /// on which to play the note, sets the pitch accordingly, and then plays the single note /// or in the case of a lead chord, it plays all notes of the chord /// /// scale is the 12th root of 2, or 1 semitone step, the basis assumes its at C (first note) of /// the scale. It is precomputed, and reset each time a note tries to play to prevent weird offsets /// /// FUTURE WORK: Precompute all scale^notevals and use that instead of Math.Pow() /// </summary> public void Play(IMusicalValue leadValue, IMusicalValue melodyValue) { float scale = 1.059463f;// Mathf.Pow(2f, 1.0f / 12f); // Play the sound on the next voice (And pass envelope modifications) //Base chords and individual notes for lead if (leadValue is Chord) { Chord leadChord = leadValue as Chord; //Debug.Log("Chord Cast"); foreach (Tone note in leadChord.Notes) { _samplerVoices[_nextVoiceIndex].Pitch = Mathf.Pow(scale, (float)note - 1); _samplerVoices[_nextVoiceIndex].Play(LeadInstrument, _attackLead, _sustainLead, _releaseLead); ++_nextVoiceIndex; _nextVoiceIndex = (_nextVoiceIndex + 1) % _samplerVoices.Length; } } else if (leadValue is Note) { //Playing a single note Note leadNote = leadValue as Note; _samplerVoices[_nextVoiceIndex].Pitch = Mathf.Pow(scale, (float)leadNote.Value - 1); if (leadNote.Value == Tone.Rest) { _samplerVoices[_nextVoiceIndex].Play(RestSpacer, _attackLead, _sustainLead, _releaseLead); } else { //Debug.Log("Note Cast and played"); _samplerVoices[_nextVoiceIndex].Play(LeadInstrument, _attackLead, _sustainLead, _releaseLead); } ++_nextVoiceIndex; _nextVoiceIndex = (_nextVoiceIndex + 1) % _samplerVoices.Length; } if (melodyValue is Note) { //Playing a single note Note melodyNote = melodyValue as Note; _samplerVoices[_nextVoiceIndex].Pitch = Mathf.Pow(scale, (float)melodyNote.Value - 1); //Debug.Log("playing melody note" + melodyNote.Value); if (melodyNote.Value == Tone.Rest) { _samplerVoices[_nextVoiceIndex].Play(RestSpacer, _attackMelody, _sustainMelody, _releaseMelody); } else { _samplerVoices[_nextVoiceIndex].Play(MelodyInstrument, _attackMelody, _sustainMelody, _releaseMelody); } ++_nextVoiceIndex; _nextVoiceIndex = (_nextVoiceIndex + 1) % _samplerVoices.Length; } //wrap nextvoice around if it exceeds max }
/// <summary> /// Generates a Melody using the notes in this bar (lead) and a melody pattern /// </summary> private List <IMusicalValue> GetMelodyBar(List <IMusicalValue> bar, List <int?> pattern) { IMusicalValue barChord = bar[(int)Beat.One]; Note rootBarNote = CurrentMood.TonicNote; if (barChord is Chord) { rootBarNote = Theory.GetNote(((Chord)barChord).Notes[0]); } else if (barChord is Note) { rootBarNote = (Note)barChord; if (rootBarNote.Value == Tone.Rest) { rootBarNote = CurrentMood.TonicNote; } } else { Debug.Log("Cannot determine the root note or chord for this bar. Shouldnt happen."); } List <IMusicalValue> newMelodyBar = new List <IMusicalValue>(); for (int n = 0; n < pattern.Count; n++) { if (pattern[n] != null) { newMelodyBar.Add(Theory.GetNextNoteByInterval(rootBarNote, (int)pattern[n])); } else { newMelodyBar.Add(Theory.Rest); } } return(newMelodyBar); }
/// <summary> /// Step each track forward one position and pass the notevalues to the sampler /// at that position /// </summary> public void Step() { IMusicalValue leadValue = LeadTrack.Dequeue(); IMusicalValue melodyValue = MelodyTrack.Dequeue(); Sampler.Play(leadValue, melodyValue); if (LeadTrack.Count < 2) { //Changing mood at some point within this MusicGenerator MusicGen = MusicGenerator.GetInstance(); Metronome metro = FindObjectOfType <Metronome>(); MusicGen.GetMood(); if (MusicGen.CurrentMood != currentMood) { Debug.Log("CHANGING MOOD"); MusicGen.Generate(); currentMood = MusicGen.CurrentMood; var emptyBar = MusicGen.GetBar(); foreach (IMusicalValue note in emptyBar) { LeadTrack.Enqueue(note); MelodyTrack.Enqueue(note); } metro.bpm = currentMood.Tempo; Sampler.LeadInstrument = currentMood.LeadInstrumentSample; Sampler.MelodyInstrument = currentMood.MelodyInstrumentSample; Sampler.SetASR(currentMood.ASRSettings); } //else //{ // //slow down as we fade out // metro.bpm /= 2; //} GetNextTracks(); } }