public void SpawnObjects(double tick, double beatsPerSecond) { if (index.note >= notes.Count) { return; //end of song } Song.Note nextNote = notes[index.note]; double tenSecondsInTicks = beatsPerSecond * 3 * resolution; if (nextNote.timestamp < tick + MetersToTickDistance(4f)) //spawn tick + 10 seconds? { //Debug.Log("New Note"); try { bool longNote = (nextNote.duration > 0); int poolNumber = (int)nextNote.fred + (longNote ? 5 : 0); NoteModel noteModel = pool.note[poolNumber][index.noteModel[poolNumber] % pool.noteSize]; GameObject newNote = noteModel.gameObject; noteModel.myTransform.rotation = cam.rotation; newNote.SetActive(true); NoteInstance noteInstance = pool.noteInstance[index.noteInstance % pool.noteInstanceSize]; index.noteInstance++; noteInstance.Update(noteModel, nextNote.timestamp, nextNote.fred, nextNote.duration, nextNote.star, nextNote.hammerOn); noteInstance.seen = false; activeNotes.Add(noteInstance); index.note++; index.noteModel[poolNumber]++; SpawnObjects(tick, beatsPerSecond); } catch (System.Exception e) { Debug.LogError(e.Message + " - " + e.StackTrace); } } }
public double outputToMidi(Song output) { //5 Tracks (Just in case; so far MIDIOut is currently utilizing 2: 1 for instrument and another for notes). Each track added to sequence right after Track[] track = new Track[5]; double songLen = 0; for (int i = 0; i < 5; i++) { track[i] = new Track(); sequence.Add(track[i]); } //Set the tempo (assuming Song.Tempo is in bpm) tempoBuilder.Tempo = (int)(1.0 / output.Tempo * 60000000); tempoBuilder.Build(); track[0].Insert(0, tempoBuilder.Result); //Set instrument /*builder.Command = ChannelCommand.ProgramChange; * //builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano; * builder.Data2 = 0; * builder.Build(); * track[1].Insert(0, builder.Result);*/ //Tick position int pos = 0; //Note length int len = 0; //MidiChannel number int c = 1; //Set MidiChannel number to 1 builder.MidiChannel = c; //Iterate through the chord voice and turn them on; Each iteration will save the note and length values int startOfSegment = 0; for (int i = 0; i < output.songData.Count; i++) { startOfSegment = pos; for (int j = 0; j < output.songData[i].chordPattern.Count; j++) { //Reset channel values to stop outOfBoundsException : Austin c = 1; builder.MidiChannel = c; foreach (var item in (output.songData[i].chordPattern[j].chordVoice)) { String note = item.noteValue; //C, C#, D, D#, E, F, F#, G, G#, A, A# len = item.length; //in 16th notes //Switch note on builder.Command = ChannelCommand.ProgramChange; if (output.Genre == "Generic" || output.Genre == "Jazz") { builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano; } else if (output.Genre == "Classical") { builder.Data1 = (int)GeneralMidiInstrument.Violin; } else if (output.Genre == "4-Chord Pop/Rock") { builder.Data1 = (int)GeneralMidiInstrument.ElectricGuitarMuted; } builder.Data2 = 0; builder.Build(); track[1].Insert(pos, builder.Result); builder.Command = ChannelCommand.NoteOn; builder.Data1 = midiValOfNote(note); if (output.Genre == "Generic") { builder.Data2 = 100; } else if (output.Genre == "Classical") { builder.Data2 = 80; } else if (output.Genre == "Jazz") { builder.Data2 = 110; } else if (output.Genre == "4-Chord Pop/Rock") { builder.Data2 = 120; } builder.Build(); //Build the message track[1].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos' //Increment MIDI channel by 1 c += 1; builder.MidiChannel = c; }//endforeach /*Tick position increment; This will be based on the last note of the previous chord, but I think it's safe to assume that its length will be the same as the rest of the chord tones of that chord. * PpqnClock.PpqnMinValue is the minimum PPQ value (24) set by the class library PpqnClock.*/ songLen += len / 4; pos += (PpqnClock.PpqnMinValue / 4 * len); c = 1; builder.MidiChannel = c; foreach (var item in (output.songData[i].chordPattern[j].chordVoice)) { String note = item.noteValue; len = item.length; //Set Note Off builder.Command = ChannelCommand.NoteOff; builder.Data1 = midiValOfNote(note); builder.Data2 = 0; //Set volume to mute builder.Build(); //Build the message track[1].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos' //Increment MIDI channel by 1 c += 1; builder.MidiChannel = c; //songLen += item.length / 16; } //endforeach } //endfor for (int q = 0; q < output.songData[i].melodies.Count(); q++) { pos = startOfSegment; for (int j = 0; j < output.songData[i].melodies[q].melodicLine.Count(); j++) { Song.Note outputNote = output.songData[i].melodies[q].melodicLine[j]; String note = outputNote.noteValue; int noteLength = outputNote.length; //in 16th notes //Switch note on builder.Command = ChannelCommand.ProgramChange; if (output.Genre == "Generic") { builder.Data1 = (int)GeneralMidiInstrument.ElectricGuitarJazz; } else if (output.Genre == "Classical") { builder.Data1 = (int)GeneralMidiInstrument.Violin; } else if (output.Genre == "Twelve-tone") { builder.Data1 = (int)GeneralMidiInstrument.AcousticGrandPiano; } else if (output.Genre == "Jazz") { builder.Data1 = (int)GeneralMidiInstrument.AltoSax; } else if (output.Genre == "4-Chord Pop/Rock" && q == 0) { builder.Data1 = (int)GeneralMidiInstrument.ChoirAahs; } else if (output.Genre == "4-Chord Pop/Rock" && q == 1) { builder.Data1 = (int)GeneralMidiInstrument.ElectricBassPick; } builder.Data2 = 0; builder.Build(); track[q + 2].Insert(pos, builder.Result); builder.Command = ChannelCommand.NoteOn; builder.Data1 = midiValOfNote(note); builder.Data2 = 127; //Set volume to max builder.Build(); //Build the message track[q + 2].Insert(pos, builder.Result); //Insert into Track 1 at tick position 'pos' //Increment MIDI channel by 1 pos += (PpqnClock.PpqnMinValue / 4 * noteLength); //Set Note Off builder.Command = ChannelCommand.NoteOff; builder.Data1 = midiValOfNote(note); builder.Data2 = 0; //Set volume to mute builder.Build(); //Build the message track[q + 2].Insert(pos, builder.Result); } } }//endfor //Submits file to the C:\BlottoBeats Folder where it is stored until another song is generated /*if (!Directory.Exists(@"C:\BlottoBeats")) * { * Directory.CreateDirectory(@"C:\BlottoBeats"); * * }*/ if (File.Exists("temp.mid")) { File.Delete("temp.mid"); } sequence.Save("temp.mid"); return(((double)pos) / (PpqnClock.PpqnMinValue / 4) / 4 / output.Tempo * 60); //Code to play sequence in client. Currently not functioning //s.Sequence = sequence; //s.Start(); }
private int LoadChartNotes(string[] chart, int i, List <Song.Note> list, uint resolution) { int timeout = 100000; while (i < timeout) { if (chart[i].Contains("{")) { //Debug.Log("Start reading Notes"); i++; break; } i++; } uint starPowerEndsAt = 0; while (i < timeout) { if (chart[i].Contains("}")) { //Debug.Log("End reading Notes"); break; } string line = chart[i]; if (line.Contains(" = ")) { string[] splitted = line.Split(new string[] { " = " }, System.StringSplitOptions.None); string[] noteSplitted = splitted[1].Split(" "[0]); uint timestamp = uint.Parse(splitted[0]); if (noteSplitted[0] == "N") { bool hammeron = false; uint fred = uint.Parse(noteSplitted[1]); Song.Note previousNote = null; if (list.Count > 0) { previousNote = list[list.Count - 1]; if (previousNote.timestamp == timestamp) //double notes no hammeron { previousNote.hammerOn = false; } else { hammeron = (timestamp < previousNote.timestamp + (resolution / 2)) && (previousNote.fred != fred) && (previousNote.timestamp != timestamp); } } if (uint.Parse(noteSplitted[1]) < 5) { list.Add(new Song.Note(timestamp, fred, uint.Parse(noteSplitted[2]), timestamp <= starPowerEndsAt, hammeron)); } } if (noteSplitted[0] == "S") { starPowerEndsAt = timestamp + uint.Parse(noteSplitted[2]); //also set previous note to star int traceBack = 1; while (traceBack < 5) { if (list[list.Count - traceBack].timestamp == timestamp) { list[list.Count - traceBack].star = true; traceBack++; continue; } break; } } } i++; } return(i); }