// Invoke the Beat event private void OnBeat() { if (BeatEvent != null) { BeatEvent.Invoke(); } }
private void OnBeatEvent(BeatEvent beatEvent) { if (context.rootNote != rootNote || context.scaleType != scaleType) { UpdateScale(rootNote, scaleType); } }
private void OnBeatEvent(BeatEvent beatEvent) { Queue <AcademicChord> academicChordsQueue = context.academicChordsQueue; PlayableSoundQueue queue = context.playableSoundQueue; while (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count > 0) { AcademicChord academicChord = academicChordsQueue.Dequeue(); PlayableSound lastSound = queue.GetLastSound(); int timeQuantumNumber = beatEvent.timeQuantumNumber; if (lastSound != null) { timeQuantumNumber = lastSound.startTimeQuantumNumber + lastSound.durationTimeQuanta; } float volume = beatEvent.isStrong ? 1f : 0.75f; for (int i = 0; i < academicChord.notes.Length; ++i) { Note chordNote = academicChord.notes[i]; Pitch pitch = new Pitch(chordNote, (i == 0 || chordNote > academicChord.notes[0]) ? 4 : 5); queue.AddSound(new PlayableSound(pitch, volume, timeQuantumNumber, context.beatManager.timeQuantaPerBeat)); } } if (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count == 0) { Debug.LogWarning("Playable sounds queue is not full, but academic chords queue is empty"); } }
private static BeatEvent[] CreatePlayerSequence(int numberOfBeats) { //creates a sequence of inputs of the appropriate difficulty //considers how many actions a player will have to make at once //will later divide between the different action inputs involved float relativeTime = 0.0f; float timeLimit = (float)(numberOfBeats / 4); int curBeat = 0; List <BeatEvent> beatList = new List <BeatEvent>(); //adds up to number of bars while (relativeTime < timeLimit) { int notesAtOnce = Random.Range(1, 3); if (curBeat % 16 == 0) { notesAtOnce = 2; } else { notesAtOnce = 1; } BeatEvent beat = new BeatEvent(4, notesAtOnce, curBeat); //add it to the time relativeTime += 1.0f / (float)beat.GetDuration(); curBeat += 16 / beat.GetDuration(); beatList.Add(beat); } //TODO maybe to array is not needed return(beatList.ToArray()); }
private void Start() { _audioSource = GetComponent <AudioSource>(); if (null != BeatEvent) { BeatEvent.Invoke(_currentBeat, _accentBeats[(int)_currentBeat]); } }
void assignTrack(float[] delays) { BeatEvent[] events = new BeatEvent[] { CommonEventFactory.getNextStateEvent(this), }; float[] deltas = delays; this.tracker.assignEvents(events, deltas); }
void assignTrack(float[] delays) { BeatEvent[] events = new BeatEvent[]{ CommonEventFactory.getNextStateEvent(this), }; float[] deltas = delays; this.tracker.assignEvents (events, deltas); }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[deltas.Length]; for (int i = 0; i < events.Length; i++) { events[i] = CommonEventFactory.getDelegatedEvent (PewLambda ()); } events [events.Length - 1] = CommonEventFactory.getNoOp (); track.assignEvents (events, deltas); }
private void OnBeatEvent(BeatEvent beatEvent) { Queue <AcademicChord> queue = context.academicChordsQueue; while (queue.Count < MAX_QUEUE_SIZE) { int index = Random.Range(0, context.academicChords.Length); queue.Enqueue(context.academicChords[index]); } }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[deltas.Length]; for (int i = 0; i < events.Length; i++) { events[i] = CommonEventFactory.getDelegatedEvent(PewLambda()); } events [events.Length - 1] = CommonEventFactory.getNoOp(); track.assignEvents(events, deltas); }
private void DynamicLevelMusicVolumes(BeatEvent e) { previousVolumes = new List <float>(); previousVolumes.Add(levelMusicSources[0].volume); if (levelMusicSources.Count >= 2) { previousVolumes.Add(levelMusicSources[1].volume); levelMusicVolumes[1] = Mathf.Clamp((float)Services.GameData.totalFilledMapTiles / (float)Services.GameData.totalMapTiles, 0.0f, BASEMUSICVOLUME); } if (levelMusicSources.Count >= 4) { previousVolumes.Add(levelMusicSources[2].volume); levelMusicVolumes[2] = Mathf.Clamp(Services.GameData.productionRates[0], 0.0f, BASEMUSICVOLUME); previousVolumes.Add(levelMusicSources[3].volume); levelMusicVolumes[3] = Mathf.Clamp(Services.GameData.productionRates[1], 0.0f, BASEMUSICVOLUME); } if (levelMusicSources.Count >= 6) { previousVolumes.Add(levelMusicSources[4].volume); levelMusicVolumes[4] = Mathf.Clamp(2.0f / Services.GameData.distancesToOpponentBase[0], 0.0f, BASEMUSICVOLUME); previousVolumes.Add(levelMusicSources[5].volume); levelMusicVolumes[5] = Mathf.Clamp(2.0f / Services.GameData.distancesToOpponentBase[1], 0.0f, BASEMUSICVOLUME); } if (levelMusicSources.Count >= 7) { for (int i = 6; i < levelMusicSources.Count; i++) { previousVolumes.Add(levelMusicSources[i].volume); levelMusicVolumes[i] = Mathf.Clamp(Services.GameData.secondsSinceMatchStarted / (5.0f * 60f), 0.0f, BASEMUSICVOLUME); } } for (int i = 0; i < levelMusicSources.Count; i++) { AudioSource to_change = levelMusicSources[i]; float starting_value = previousVolumes[i]; float new_value = levelMusicVolumes[i]; StartCoroutine(Coroutines.DoOverEasedTime(Services.Clock.HalfLength() + Services.Clock.QuarterLength(), Easing.Linear, t => { float new_volume = Mathf.Lerp(starting_value, new_value, t); to_change.volume = new_volume; })); } }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[deltas.Length]; for (int i = 0; i < events.Length - 1; i++) { events[i] = getAttackEvent(); } events [events.Length - 1] = CommonEventFactory.getNoOp(); track.assignEvents(events, deltas); }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[deltas.Length]; for(int i = 0 ; i < events.Length - 1; i++) { events[i] = getAttackEvent (); } events [events.Length - 1] = CommonEventFactory.getNoOp (); track.assignEvents (events, deltas); }
public ChordSegment(Key key, ChordSegment previousChordSegment, BeatEvent beat, byte lowestPitch) { Key = key; PreviousChordSegment = previousChordSegment; Beat = beat; NotesInLevel2Beats = new NotesInSegment(beat.AbsoluteRealTime, beat.Length, lowestPitch); BestPrevious = new int[24]; Scores = new double[24]; BaseScores = new double[24]; }
private void OnBeatEvent(BeatEvent beatEvent) { Queue <AcademicChord> queue = context.academicChordsQueue; while (queue.Count < MAX_QUEUE_SIZE) { int index = Random.Range(0, PHRASES.Length); foreach (int chordNumber in PHRASES[index]) { queue.Enqueue(context.academicChords[chordNumber - 1]); } } }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[]{ getAttackEvent (), CommonEventFactory.getNoOp () }; float[] deltas = new float[]{ beatOffset, beatsBetweenAttack }; track.assignEvents (events, deltas); track.AdditionalOffset (beatOffset); }
protected override void assignTrack() { BeatEvent[] events = new BeatEvent[] { getAttackEvent(), CommonEventFactory.getNoOp() }; float[] deltas = new float[] { beatOffset, beatsBetweenAttack }; track.assignEvents(events, deltas); track.AdditionalOffset(beatOffset); }
/// <summary> /// Audio callback, called ever ~20ms. About as close to the beat as we can get. /// </summary> /// <param name="data"></param> /// <param name="channels"></param> private void Update() { double beat = (_audioSource.time) / (.5 * 60.0 / _bpm); beat %= 8; _currentBeatUnQuantized = beat; beat = (int)beat; if (lastTime != beat) { BeatEvent.Invoke((int)beat, _accentBeats[(int)beat]); lastTime = (int)beat; } if (_isPlaying && !_audioSource.isPlaying) { _roundManager.EndRound(); _isPlaying = false; } _timeElapsed += Time.deltaTime; }
private void OnBeatEvent(BeatEvent beatEvent) { Queue <AcademicChord> academicChordsQueue = context.academicChordsQueue; PlayableSoundQueue queue = context.playableSoundQueue; while (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count > 0) { AcademicChord academicChord = academicChordsQueue.Dequeue(); PlayableSound lastSound = queue.GetLastSound(); int timeQuantumNumber = beatEvent.timeQuantumNumber; if (lastSound != null) { timeQuantumNumber = lastSound.startTimeQuantumNumber + lastSound.durationTimeQuanta; } List <Pitch> pitches = new List <Pitch> { new Pitch(academicChord.notes[0], 4), new Pitch(academicChord.notes[1], academicChord.notes[1] > academicChord.notes[0] ? 4 : 5), new Pitch(academicChord.notes[2], academicChord.notes[2] > academicChord.notes[0] ? 4 : 5), }; List <int> indices = GetIndices(pitches.Count, context.beatManager.timeQuantaPerBeat / SOUND_DURATION_TIME_QUANTA); bool strong = true; foreach (int index in indices) { float volume = strong ? 1f : 0.5f; strong = false; queue.AddSound(new PlayableSound(pitches[index], volume, timeQuantumNumber, SOUND_DURATION_TIME_QUANTA)); timeQuantumNumber += SOUND_DURATION_TIME_QUANTA; } } if (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count == 0) { Debug.LogWarning("Playable sounds queue is not full, but academic chords queue is empty"); } }
private void OnBeatEvent(BeatEvent beatEvent) { Queue <AcademicChord> academicChordsQueue = context.academicChordsQueue; PlayableSoundQueue queue = context.playableSoundQueue; while (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count > 0) { AcademicChord academicChord = academicChordsQueue.Dequeue(); PlayableSound lastSound = queue.GetLastSound(); int timeQuantumNumber = beatEvent.timeQuantumNumber; if (lastSound != null) { timeQuantumNumber = lastSound.startTimeQuantumNumber + lastSound.durationTimeQuanta; } int beatCounter = timeQuantumNumber / context.beatManager.timeQuantaPerBeat; bool isStrong = beatCounter % context.beatManager.measure == 0; float volume = isStrong ? 1f : 0.75f; if (_useMelody) { for (int i = 0; i < academicChord.notes.Length; ++i) { Note chordNote = academicChord.notes[i]; Pitch pitch = new Pitch(chordNote, (i == 0 || chordNote > academicChord.notes[0]) ? 4 : 5); queue.AddSound(new PlayableSound(pitch, volume, timeQuantumNumber, context.beatManager.timeQuantaPerBeat)); } } if (_useBass) { Pitch bass = new Pitch(academicChord.notes[0], 2); queue.AddSound(new PlayableSound(bass, volume, timeQuantumNumber, context.beatManager.timeQuantaPerBeat)); } if (_useCounterMelody) { List <Pitch> arpeggioPitches = new List <Pitch>(); for (int i = 0; i < academicChord.notes.Length; ++i) { Note chordNote = academicChord.notes[i]; arpeggioPitches.Add(new Pitch(chordNote, (i == 0 || chordNote > academicChord.notes[0]) ? 6 : 7)); } ; const int arpeggioNoteDurationTimeQuanta = 8; List <int> indices = GetIndices(arpeggioPitches.Count, context.beatManager.timeQuantaPerBeat / arpeggioNoteDurationTimeQuanta); int arpeggioTimeQuantumNumber = timeQuantumNumber; foreach (int index in indices) { queue.AddSound(new PlayableSound(arpeggioPitches[index], volume, arpeggioTimeQuantumNumber, arpeggioNoteDurationTimeQuanta)); arpeggioTimeQuantumNumber += arpeggioNoteDurationTimeQuanta; } } } if (queue.count < MAX_QUEUE_SIZE && academicChordsQueue.Count == 0) { Debug.LogWarning("Playable sounds queue is not full, but academic chords queue is empty"); } }
/// <summary> /// Assigns the events. TODO: copy the events and deltas passed in, otherwise these are still pointers /// and can change unexpectedly... (so don't change them plz) /// </summary> /// <param name="events">Events.</param> /// <param name="deltas">Deltas.</param> public void assignEvents(BeatEvent[] events, float[] deltas) { this.events = events; this.deltas = deltas; }
private void FireBeatEvent() { BeatEvent beatEvent = new BeatEvent(_lastTimeQuantumTime, _timeQuantumCounter, _beatCounter, _beatCounter % _measure == 0); _beatEventListeners.ForEach(listener => listener.action.Invoke(beatEvent)); }
void bounceToBeat(BeatEvent be) { // Debug.Log("BOUNCE GET"); //if(GameManager.instance.inputDevice.LeftStickX > -1 * stickThreshold) StartCoroutine("bounce"); }
public void PlayEvent(int i) { BeatEvent?.Invoke(i); }
public static Model Parse(string filename, int frameRateMillis = 50, bool showBeats = false, bool showChords = false, bool randomize = true) { var track = new Track(); var midi = new Model { Tracks = new[] { track } }; byte[] fileBytes = File.ReadAllBytes(filename); var random = new Random(123456); var timeMillis = 0; var beatLength = 12 * frameRateMillis; var actualNotes = new NoteOn[16, 128]; var actualPercussion = new NoteOn[128]; var instrumentsOnChannels = new MusicalInstrument[16]; for (byte i = 0; i < Model.NumberOfChannels; i++) { track.Channels[i].Events.Add(new Controller { AbsoluteRealTime = TimeSpan.Zero, AbsoluteTime = 0, ChannelNumber = i, ControllerNumber = 7, ControllerValue = 64 }); } for (int i = 0; i < fileBytes.Length; i += 4) { var eventType = (EventType)(fileBytes[i] & 0x0F); if (i == 400 * 4) { track.MetaEvents.Add(new ImprovisationStartMetaEvent { AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis) }); } switch (eventType) { case EventType.NoteOnEvent: { var channel = (byte)(fileBytes[i] >> 4); var pitch = (byte)(fileBytes[i + 1] + ClusterRanges.Min((InstrumentCluster)channel)); var instrument = (MusicalInstrument)Instrument.TypicalInstrument((InstrumentCluster)channel); var volume = fileBytes[i + 2] / 128.0 - 1; volume = Math.Pow(volume, 2) * Math.Sign(volume); if (randomize) { volume = (byte)(volume * (0.9 + random.NextDouble() * 0.1)); } volume = 64.0 + 64.0 * volume; if (!instrument.Equals(instrumentsOnChannels[channel])) { track.Channels[channel].Events.Add(new InstrumentChange { AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis - 1), AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), ChannelNumber = channel, Instrument = instrument }); instrumentsOnChannels[channel] = instrument; } var prevNote = actualNotes[channel, pitch]; if (prevNote != null) { TimeSpan end; if (timeMillis < prevNote.AbsoluteRealTime.TotalMilliseconds + 5000) { end = TimeSpan.FromMilliseconds(timeMillis); } else { end = prevNote.AbsoluteRealTime + TimeSpan.FromMilliseconds(5000); } prevNote.End = end; prevNote.RealTimeLength = end - prevNote.AbsoluteRealTime; prevNote.Length = (uint)(prevNote.RealTimeLength.TotalMilliseconds / frameRateMillis); track.Channels[prevNote.ChannelNumber].Events.Add(new NoteOff { ChannelNumber = prevNote.ChannelNumber, AbsoluteRealTime = prevNote.End, AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), NoteNumber = prevNote.NoteNumber, Velocity = 64 }); } var note = new NoteOn { ChannelNumber = channel, NoteNumber = pitch, Volume = (byte)Calc.Clamp((int)(volume + 0.5), 0, 127), AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), Length = (uint)(4800 / frameRateMillis), AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis), End = TimeSpan.FromMilliseconds(timeMillis + 4800), RealTimeLength = TimeSpan.FromMilliseconds(4800) }; track.Channels[channel].Events.Add(note); actualNotes[channel, pitch] = note; break; } case EventType.NoteOffEvent: { var channel = (byte)fileBytes[i + 2]; var pitch = (byte)(fileBytes[i + 1] + ClusterRanges.Min((InstrumentCluster)channel)); var note = actualNotes[channel, pitch]; if (note == null) //throw new Exception("neni na co navazovat"); { continue; } TimeSpan end; if (timeMillis < note.AbsoluteRealTime.TotalMilliseconds + 5000) { end = TimeSpan.FromMilliseconds(timeMillis); } else { end = note.AbsoluteRealTime + TimeSpan.FromMilliseconds(5000); } note.End = end; note.RealTimeLength = end - note.AbsoluteRealTime; note.Length = (uint)(note.RealTimeLength.TotalMilliseconds / frameRateMillis); track.Channels[note.ChannelNumber].Events.Add(new NoteOff { ChannelNumber = note.ChannelNumber, AbsoluteRealTime = note.End, AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), NoteNumber = note.NoteNumber, Velocity = 64 }); actualNotes[channel, pitch] = null; break; } case EventType.PercussionOnEvent: { var percussionType = (byte)(fileBytes[i + 1] + Percussion.MinNoteNumber); //var volume = (byte)(clusterVolumes[InstrumentCluster.Percussion] * 128.0); var volume = fileBytes[i + 2] / 128.0 - 1; volume = Math.Pow(volume, 2) * Math.Sign(volume); if (randomize) { volume = (byte)(volume * (0.9 + random.NextDouble() * 0.1)); } volume = 64.0 + 64.0 * volume; var prevNote = actualPercussion[percussionType]; if (prevNote != null) { TimeSpan end; if (timeMillis < prevNote.AbsoluteRealTime.TotalMilliseconds + 4800) { end = TimeSpan.FromMilliseconds(timeMillis); } else { end = prevNote.AbsoluteRealTime + TimeSpan.FromMilliseconds(4800); } prevNote.End = end; prevNote.RealTimeLength = end - prevNote.AbsoluteRealTime; prevNote.Length = (uint)(prevNote.RealTimeLength.TotalMilliseconds / frameRateMillis); track.Channels[prevNote.ChannelNumber].Events.Add(new NoteOff { ChannelNumber = prevNote.ChannelNumber, AbsoluteRealTime = prevNote.End, AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), NoteNumber = prevNote.NoteNumber, Velocity = 64 }); } var note = new NoteOn { ChannelNumber = Channel.PercussionChannelNumber, NoteNumber = percussionType, Volume = (byte)Calc.Clamp((int)(volume + 0.5), 0, 127), AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), Length = (uint)(4800 / frameRateMillis), AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis), End = TimeSpan.FromMilliseconds(timeMillis + 4800), RealTimeLength = TimeSpan.FromMilliseconds(4800) }; track.Channels[Channel.PercussionChannelNumber].Events.Add(note); actualPercussion[percussionType] = note; break; } case EventType.PercussionOffEvent: { var percussionType = (byte)(fileBytes[i + 1] + Percussion.MinNoteNumber); var percussion = actualPercussion[percussionType]; if (percussion == null) //throw new Exception("neni na co navazovat"); { continue; } TimeSpan end; if (timeMillis < percussion.AbsoluteRealTime.TotalMilliseconds + 4800) { end = TimeSpan.FromMilliseconds(timeMillis); } else { end = percussion.AbsoluteRealTime + TimeSpan.FromMilliseconds(4800); } percussion.End = end; percussion.RealTimeLength = end - percussion.AbsoluteRealTime; percussion.Length = (uint)(percussion.RealTimeLength.TotalMilliseconds / frameRateMillis); track.Channels[percussion.ChannelNumber].Events.Add(new NoteOff { ChannelNumber = percussion.ChannelNumber, AbsoluteRealTime = percussion.End, AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5), NoteNumber = percussion.NoteNumber, Velocity = 64 }); actualPercussion[percussionType] = null; break; } case EventType.SmallSpaceEvent: { var tempo = fileBytes[i + 1] | fileBytes[i + 2] << 8; var chord = fileBytes[i + 3]; if (timeMillis % beatLength == 0 && chord != 24) { var beat = new BeatEvent { AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5 + beatLength), AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis + beatLength), Length = TimeSpan.FromMilliseconds(beatLength), Chord = new Key(chord), Level = 2 }; track.MetaEvents.Add(beat); } timeMillis += frameRateMillis /** tempo / 600.0*/; break; } case EventType.BigSpaceEvent: { var tempo = fileBytes[i + 1] | fileBytes[i + 2] << 8; var chord = fileBytes[i + 3]; if (timeMillis % beatLength == 0 && chord != 24) { var beat = new BeatEvent { AbsoluteTime = (uint)(timeMillis / frameRateMillis + 0.5 + beatLength), AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis + beatLength), Length = TimeSpan.FromMilliseconds(beatLength), Chord = new Key(chord), Level = 2 }; track.MetaEvents.Add(beat); } timeMillis += frameRateMillis * 6 /** tempo / 600.0*/; break; } case EventType.EndEvent: { timeMillis += frameRateMillis * 200; break; } } } track.MetaEvents.Add(new EndOfTrack { AbsoluteRealTime = TimeSpan.FromMilliseconds(timeMillis + 1200) }); { var collector = new VolumeChangeCollector(midi); collector.DetermineVolumes(); } { var collector = new InstrumentChangeCollector(midi); collector.DetermineInstruments(); } if (showBeats) { Normalizer.AddBeats(midi, false, 32); } if (showChords) { var analyzer = new ChordAnalyzer(midi); analyzer.AddChordNotesToModel(48); } if (randomize) { foreach (var note in midi.EventsOfType <NoteOn>()) { var startOffset = random.Next(10); var lengthChange = 0.1 * random.NextDouble() * note.RealTimeLength.TotalMilliseconds; note.AbsoluteRealTime += TimeSpan.FromMilliseconds(startOffset); note.RealTimeLength -= TimeSpan.FromMilliseconds(lengthChange); note.End -= TimeSpan.FromMilliseconds(startOffset + lengthChange); } } ChannelPlayabilityChecker.Check(midi); midi.Length = midi.EventsOfType <EndOfTrack>().Max(e => e.AbsoluteRealTime); return(midi); }
public static void ScheduleNextMeasure(BeatEvent e) { scheduledMeasureEvents.Add (e); }
private void OnEnableCConstantBeatDetection() { _historyBuffer = new float[Mathf.FloorToInt(SampleRate / sampleCount)]; onBeatDetected = new BeatEvent(); }
/// <summary> /// Calculates the meter and saves it in BeatEvents /// </summary> /// <param name="midi"></param> public static void CalculateMetre(Model midi) { var offset = CalculateMeterFitnessMetric(midi); //use beats that are already in the midi file if (midi.GoodnessOfMetreFit > 0.4) { midi.IsNormalizedByMidiItself = true; CalculateImplicitMetre(); } // else detect the meter by the detector else { midi.IsNormalizedByMidiItself = false; PadNotesToZero(midi); var metre = Analyze(midi).Select(TimeSpan.FromMilliseconds).ToList(); for (var i = metre.Sum(t => t.TotalMilliseconds); i <= midi.Length.TotalMilliseconds; i += metre.Last().TotalMilliseconds) { metre.Add(metre.Last()); } CreateBeatEvents(metre); var beatStrengthAnalyzer = new BeatStrengthAnalyzer(midi); beatStrengthAnalyzer.Analyze(); } var firstBeatTime = midi.EventsOfType <BeatEvent>().Min(b => b.AbsoluteRealTime); if (firstBeatTime != TimeSpan.Zero) { var beatEvent = new BeatEvent { AbsoluteRealTime = TimeSpan.Zero, Level = 2, Length = firstBeatTime }; midi.Tracks[0].MetaEvents.Add(beatEvent); } if (!midi.IsNormalizedByMidiItself) { midi.GoodnessOfMetreFit = (float)CalculateMeterFitnessOfBeatEvents(midi); } void CalculateImplicitMetre() { var baseTick = GetTicksPerBeat(midi); var end = midi.EventsOfType <EndOfTrack>().Max(e => e.AbsoluteTime); var timeSignatures = new Queue <TimeSignature>(midi.EventsOfType <TimeSignature>().OrderBy(e => e.AbsoluteTime)); var actualTimeSignature = new TimeSignature { AbsoluteTime = 0, Numerator = 4, Denominator = 4 }; var tick = baseTick * 4 / actualTimeSignature.Denominator; var barCounter = 0; if (offset > 0) { midi.Tracks[0].MetaEvents.Add(new BeatEvent { AbsoluteTime = 0, Level = 2 }); } for (var time = offset; time <= end; time += tick) { if (timeSignatures.Count > 0 && timeSignatures.Peek().AbsoluteTime <= time) { actualTimeSignature = timeSignatures.Dequeue(); barCounter = 0; tick = baseTick * 4 / actualTimeSignature.Denominator; } var level = 2; if (barCounter % actualTimeSignature.Numerator == 0) { level = 0; } else if ((actualTimeSignature.Numerator == 4 && barCounter % actualTimeSignature.Numerator == 2) || (actualTimeSignature.Numerator == 6 && barCounter % actualTimeSignature.Numerator == 3)) { level = 1; } var beat = new BeatEvent { AbsoluteTime = time, Level = (byte)level }; midi.Tracks[0].MetaEvents.Add(beat); barCounter++; } TimeCalculator.ComputeRealTimes(midi); CalculateBeatLengths(); var averageLength = midi.EventsOfType <BeatEvent>().Average(b => b.Length.TotalMilliseconds); while (averageLength > 1000) { var beats = midi.EventsOfType <BeatEvent>().ToArray(); foreach (var beat in beats) { midi.Tracks[0].MetaEvents.Add(new BeatEvent { AbsoluteRealTime = beat.AbsoluteRealTime + beat.Length.Divide(2), Level = 2 }); } CalculateBeatLengths(); averageLength = averageLength / 2; } } void CalculateBeatLengths() { var beatEvents = midi.EventsOfType <BeatEvent>().OrderBy(b => b.AbsoluteRealTime).ToArray(); for (var i = 0; i < beatEvents.Length - 1; i++) { beatEvents[i].Length = beatEvents[i + 1].AbsoluteRealTime - beatEvents[i].AbsoluteRealTime; } beatEvents[beatEvents.Length - 1].Length = beatEvents[beatEvents.Length - 2].Length; } void CreateBeatEvents(IEnumerable <TimeSpan> metre) { var time = TimeSpan.Zero; foreach (var beat in metre) { var beatEvent = new BeatEvent { AbsoluteRealTime = time, Level = 0, Length = beat }; midi.Tracks[0].MetaEvents.Add(beatEvent); time += beat; } } }
public static void ScheduleNextMeasure(BeatEvent e) { scheduledMeasureEvents.Add(e); }