Пример #1
0
        public SongStyle(SongComposer composer, Song song, MusicalScale musicalScale, float minimumNoteLength)
        {
            Composer = composer;
            Song     = song;

            RunningTime = 0;

            MusicalScale      = musicalScale;
            MinimumNoteLength = minimumNoteLength;

            ChordsTicksToHold = new int[4];
            BassMelodicStyles = new BassMelodicStyle[4];
            MelodicStyles     = new MelodicStyle[4];
            FirstDegrees      = new int[4];
            BassTimbres       = new NoteTimbre[4];
            ChordTimbres      = new NoteTimbre[4];
            MelodyTimbres     = new NoteTimbre[4];
            ChordTypes        = new ChordType[4];

            for (int i = 0; i < 4; i++)
            {
                ChordsTicksToHold[i] = -1;
                BassMelodicStyles[i] = BassMelodicStyle.None;
                MelodicStyles[i]     = MelodicStyle.None;
                FirstDegrees[i]      = -1;
                BassTimbres[i]       = NoteTimbre.None;
                ChordTimbres[i]      = NoteTimbre.None;
                MelodyTimbres[i]     = NoteTimbre.None;
                ChordTypes[i]        = ChordType.None;
            }

            LoadChords();
        }
Пример #2
0
        protected void PlayNote(int voiceNumber, float volume, MusicalNote note)
        {
            if (voiceNumber >= AudioSources.Length)
            {
                throw new ArgumentException($"You trying to play a note using voice number {voiceNumber + 1} but we only have {AudioSources.Length} dude!");
            }

            float     pitch = 1;
            AudioClip clip;

            string noteName = $"{note.Name}{note.Octave}{note.Timbre}";

            if (NoteClips
                .ContainsKey(noteName))
            {
                clip = NoteClips[noteName];
            }
            else
            {
                float       min     = float.MaxValue;
                MusicalNote closest = null;

                int requestedIndex = MusicalScale
                                     .GetNoteAbsoluteIndex(note.Name, 8, note.Octave);

                foreach (var possibleNote in AvailableNotes)
                {
                    int noteIndex = MusicalScale
                                    .GetNoteAbsoluteIndex(possibleNote.Name, 8, possibleNote.Octave);

                    int difference = Mathf.Abs(noteIndex - requestedIndex);
                    if (difference < min)
                    {
                        min     = difference;
                        closest = possibleNote;
                    }
                }

                //Debug
                //.Log($"REQUESTED '{note.Name}{note.Octave}{note.Timbre}' ACTUAL {closest.Name}{closest.Octave}{closest.Timbre}");

                clip  = NoteClips[$"{closest.Name}{closest.Octave}{note.Timbre}"];
                pitch = CalculateFrequencyRatio(closest, note);
            }

            var source = AudioSources[voiceNumber];

            source
            .Stop();
            source.clip   = null;
            source.pitch  = pitch;
            source.volume = volume;
            source.clip   = clip;
            source
            .Play();
        }
Пример #3
0
        protected float CalculateFrequencyRatio(MusicalNote fromNote, MusicalNote toNote)
        {
            string noteKey = $"{fromNote.Name}{fromNote.Octave}";

            if (!NoteFrequencies
                .ContainsKey(noteKey))
            {
                throw new ArgumentException($"'{noteKey}' does not exist in the note frequency table");
            }

            int fromIndex = MusicalScale
                            .GetNoteAbsoluteIndex(fromNote.Name, 8, fromNote.Octave);

            int toIndex = MusicalScale
                          .GetNoteAbsoluteIndex(toNote.Name, 8, toNote.Octave);

            float fromFrequency = NoteFrequencies[noteKey];

            int indexDifference = fromIndex - toIndex;

            float toFrequency = fromFrequency * Mathf.Pow(2, indexDifference / 12f);

            return(toFrequency / fromFrequency);
        }
Пример #4
0
        protected void WriteMelody()
        {
            var melodicStyle  = MelodicStyles[CurrentChunkIndex];
            var melodicTimbre = MelodyTimbres[CurrentChunkIndex];

            int          consecutiveTicksWithoutRest = 0;
            float        melodyTime         = CurrentChunkIndex * TICKS_PER_CHUNK * MinimumNoteLength;
            MusicalNote  currentNote        = null;
            float        currentNoteEndTime = 0;
            MusicalChord currentChord       = null;

            for (int tick = 0; tick < 8 * 4 * 4; tick++)
            {
                if (melodyTime < currentNoteEndTime)
                {
                    melodyTime += MinimumNoteLength;
                    continue;
                }

                // SHOULD WE REST?
                var restChooser = new ProbabilityChooser <bool>();

                restChooser
                .AddItem(true, consecutiveTicksWithoutRest);

                restChooser
                .AddItem(false, 32);

                var shouldRest = restChooser
                                 .ChooseItem();

                if (shouldRest)
                {
                    consecutiveTicksWithoutRest = 0;

                    var restLengthChooser = RestLengthChooserPerStyle[melodicStyle];

                    int ticksToRest = restLengthChooser
                                      .ChooseItem();

                    currentNoteEndTime = melodyTime + ticksToRest * MinimumNoteLength;

                    currentNote = null;

                    melodyTime += MinimumNoteLength;

                    continue;
                }

                var chord = GetChordForTime(melodyTime);

                if (chord != null)
                {
                    currentChord = chord;
                }

                var beatStrength = GetBeatStrength(melodyTime);

                int  noteTicks     = 0;
                bool stayOnOffBeat = StayOnOffBeatChooser[melodicStyle]
                                     .ChooseItem();

                if (beatStrength == BeatStrength.Off16th && !stayOnOffBeat)
                {
                    noteTicks = 1;
                }
                else if (beatStrength == BeatStrength.Off8th && !stayOnOffBeat)
                {
                    noteTicks = 2;
                }
                else
                {
                    var noteLengthChooser = NoteLengthChooserPerStyle[melodicStyle];

                    noteTicks = noteLengthChooser
                                .ChooseItem();
                }

                var  melodyNoteInChordChooser = MelodyNoteIsInChordChoosers[beatStrength];
                bool noteShouldBeInChord      = melodyNoteInChordChooser
                                                .ChooseItem();

                var  melodyNoteInScaleChooser = MelodyNoteIsInScaleChoosers[beatStrength];
                bool noteShouldBeInScale      = melodyNoteInScaleChooser
                                                .ChooseItem();

                int melodicInterval = MelodicIntervalChooser
                                      .ChooseItem();

                int currentDegree = -1;

                if (currentNote != null)
                {
                    currentDegree = MusicalScale
                                    .GetDegree(currentNote.Name);
                }

                int nextDegree = 0;

                if (noteShouldBeInChord)
                {
                    if (currentNote != null)
                    {
                        int closestDegree = 0;
                        int minDistance   = int.MaxValue;

                        foreach (var note in currentChord.Notes)
                        {
                            int ndg = MusicalScale
                                      .GetDegree(note.Name);

                            int d = Mathf
                                    .Abs(currentDegree - ndg);

                            if (d < minDistance)
                            {
                                minDistance   = d;
                                closestDegree = ndg;
                            }
                        }

                        nextDegree = closestDegree;
                    }
                    else
                    {
                        var noteIndex = UnityEngine
                                        .Random
                                        .Range(0, currentChord.Notes.Length);

                        var note = currentChord.Notes[noteIndex];

                        nextDegree = MusicalScale
                                     .GetDegree(note.Name);
                    }
                }
                else
                {
                    if (currentNote != null)
                    {
                        nextDegree = GetScaleDegree(currentDegree, melodicInterval);
                    }
                    else
                    {
                        nextDegree = GetScaleDegree(0, melodicInterval);
                    }
                }

                int octaveChange = 0;

                if (melodicInterval > 7)
                {
                    octaveChange++;
                }

                if (melodicInterval < -7)
                {
                    octaveChange--;
                }

                if (currentNote != null)
                {
                    if (melodicInterval > 0 && nextDegree < currentDegree)
                    {
                        octaveChange++;
                    }

                    if (melodicInterval < 0 && nextDegree > currentDegree)
                    {
                        octaveChange--;
                    }
                }

                currentNote = MusicalScale
                              .AscendingNotes[nextDegree];

                if (currentNote.Octave - octaveChange <= 0)
                {
                    octaveChange = 0;
                }

                if (currentNote.Octave + octaveChange >= 7)
                {
                    octaveChange = 0;
                }

                Composer
                .AddNoteToSong(Song, melodyTime, MELODY_VOICE, 1f, currentNote, melodicTimbre, octaveChange);

                consecutiveTicksWithoutRest++;

                currentNoteEndTime = melodyTime + noteTicks * MinimumNoteLength;

                melodyTime += MinimumNoteLength;
            }
        }
Пример #5
0
        protected void WriteBaseLine()
        {
            var chordTicksToHold = ChordsTicksToHold[CurrentChunkIndex];
            var bassTimbre       = BassTimbres[CurrentChunkIndex];
            var bassmelodicStyle = BassMelodicStyles[CurrentChunkIndex];

            var walkingBassLineApproachChooser = new ProbabilityChooser <int>();

            walkingBassLineApproachChooser.AddItem(-2, 1);
            walkingBassLineApproachChooser.AddItem(-1, 1);

            var walkingBassLineExitChooser = new ProbabilityChooser <int>();

            walkingBassLineExitChooser.AddItem(2, 1);
            walkingBassLineExitChooser.AddItem(1, 1);

            // GET THE CHORD EVENTS
            var chordEvents = Song.Voices[1].Events;

            // WRITE THE BASS LINE
            int octaveChange;
            int baseNoteTicksToHold = chordTicksToHold;

            switch (bassmelodicStyle)
            {
            case BassMelodicStyle.SingleNote:
                foreach (var chordEvent in chordEvents)
                {
                    octaveChange = -1;
                    if (chordEvent.Note.Octave <= 1)
                    {
                        octaveChange = 0;
                    }

                    // BASS IS VOICE 0
                    Composer
                    .AddNoteToSong(Song, chordEvent.OccursAt, BASS_VOICE, 0.75f, chordEvent.Note, bassTimbre, octaveChange);
                }

                break;

            case BassMelodicStyle.AlternatingNotes:
                baseNoteTicksToHold = chordTicksToHold / 2;

                foreach (var chordEvent in chordEvents)
                {
                    octaveChange = -1;
                    if (chordEvent.Note.Octave <= 1)
                    {
                        octaveChange = 0;
                    }

                    Composer
                    .AddNoteToSong(Song, chordEvent.OccursAt, BASS_VOICE, 0.75f, chordEvent.Note, bassTimbre, octaveChange);

                    var otherEvent = Song.Voices[3].Events.FirstOrDefault(o => o.OccursAt == chordEvent.OccursAt);

                    float secondNoteOccurs = chordEvent.OccursAt + baseNoteTicksToHold * MinimumNoteLength;

                    Composer
                    .AddNoteToSong(Song, secondNoteOccurs, BASS_VOICE, 0.75f, otherEvent.Note, bassTimbre, octaveChange);
                }
                break;

            case BassMelodicStyle.WalkingNotes:
                baseNoteTicksToHold = chordTicksToHold / 4;

                foreach (var chordEvent in chordEvents)
                {
                    var otherEvent = Song.Voices[3].Events.FirstOrDefault(o => o.OccursAt == chordEvent.OccursAt);

                    octaveChange = -1;
                    if (chordEvent.Note.Octave <= 1)
                    {
                        octaveChange = 0;
                    }

                    float time = chordEvent.OccursAt;

                    Composer
                    .AddNoteToSong(Song, time, BASS_VOICE, 0.75f, chordEvent.Note, bassTimbre, octaveChange);

                    time += baseNoteTicksToHold * MinimumNoteLength;

                    int secondNoteDegree = MusicalScale
                                           .GetDegree(otherEvent.Note.Name);

                    int nextDegree = GetScaleDegree(secondNoteDegree, walkingBassLineApproachChooser
                                                    .ChooseItem());

                    if (nextDegree > secondNoteDegree)
                    {
                        octaveChange = -1;
                    }

                    var nextNote = MusicalScale.AscendingNotes[nextDegree];

                    Composer
                    .AddNoteToSong(Song, time, BASS_VOICE, 0.75f, nextNote, bassTimbre, octaveChange);

                    time += baseNoteTicksToHold * MinimumNoteLength;

                    octaveChange = -1;
                    if (otherEvent.Note.Octave <= 1)
                    {
                        octaveChange = 0;
                    }

                    Composer
                    .AddNoteToSong(Song, time, BASS_VOICE, 0.75f, otherEvent.Note, bassTimbre, octaveChange);

                    nextDegree = GetScaleDegree(secondNoteDegree, walkingBassLineExitChooser
                                                .ChooseItem());

                    if (nextDegree < secondNoteDegree)
                    {
                        octaveChange = -1;
                    }

                    nextNote = MusicalScale.AscendingNotes[nextDegree];

                    time += baseNoteTicksToHold * MinimumNoteLength;

                    Composer
                    .AddNoteToSong(Song, time, BASS_VOICE, 0.75f, nextNote, bassTimbre, octaveChange);
                }
                break;
            }

            Song
            .SortEvents();
        }