public async Task <SongSimplification> AddSongSimplificationAsync(SongSimplification simpl) { try { Context.SongSimplifications.Add(simpl); await Context.SaveChangesAsync(); var newNotes = simpl.Notes.Where(n => n.Id == 0).ToList(); foreach (var n in newNotes) { Context.Notes.Add(n); } await Context.SaveChangesAsync(); foreach (var n in simpl.Notes) { Context.SongSimplificationNotes.Add(new SongSimplificationNote { NoteId = n.Id, SongSimplificationId = simpl.Id }); } await Context.SaveChangesAsync(); } catch (Exception fdsafasdfa) { } return(simpl); }
public static List <Melody> GetMelodiesOfSimplification(SongSimplification simpl) { var retObj = new List <Melody>(); for (byte i = 0; i < simpl.NumberOfVoices; i++) { var voiceNotes = GetNonPercusionNotesOfVoice(simpl.Notes, i); if (voiceNotes.Count == 0) { continue; } if (VoiceIsMelodic(voiceNotes)) { var melody = new Melody(voiceNotes); melody.SongSimplificationId = simpl.Id; melody.Voice = i; melody.Instrument = voiceNotes[0].Instrument; retObj.Add(melody); } } // If we couldn't find any voice that is a melody, then the melody is // given by the highest notes of the combined notes if (retObj.Count == 0) { var melody = new Melody(GetNonPercusionNotes(simpl.Notes)); melody.SongSimplificationId = simpl.Id; melody.Voice = melody.Notes[0].Voice; melody.Instrument = melody.Notes[0].Instrument; retObj.Add(melody); } return(retObj); }
public async Task <ActionResult> SimplifySongs() { var currentPage = 0; while (true) { currentPage++; var songs = await Repository.GetSongsAsync(currentPage, 3); if (songs == null) { break; } foreach (var song in songs) { var simpl = await Repository.GetSongSimplificationAsync(song.Id, 0); var simpl1 = new SongSimplification() { Notes = simpl.Notes.Select(n => n.Clone()) .OrderBy(x => x.StartSinceBeginningOfSongInTicks).ToList(), SimplificationVersion = 1, SongId = simpl.SongId, NumberOfVoices = simpl.NumberOfVoices }; simpl1.Notes = SimplificationUtilities.RemoveBendings(simpl1.Notes); simpl1.Notes = SimplificationUtilities.RemoveEmbelishments(simpl1.Notes); await Repository.AddSongSimplificationAsync(simpl1); var simpl2 = new SongSimplification() { Notes = simpl1.Notes.Select(n => n.Clone()) .OrderBy(x => x.StartSinceBeginningOfSongInTicks).ToList(), SimplificationVersion = 2, SongId = simpl.SongId, NumberOfVoices = simpl.NumberOfVoices }; simpl2.Notes = SimplificationUtilities.RemoveNonEssentialNotes(simpl2.Notes, 80); await Repository.AddSongSimplificationAsync(simpl2); var simpl3 = new SongSimplification() { Notes = simpl2.Notes.Select(n => n.Clone()) .OrderBy(x => x.StartSinceBeginningOfSongInTicks).ToList(), SimplificationVersion = 3, SongId = simpl.SongId, NumberOfVoices = simpl.NumberOfVoices }; simpl3.Notes = SimplificationUtilities.RemoveNonEssentialNotes(simpl3.Notes, 80); await Repository.AddSongSimplificationAsync(simpl3); } } return(null); }
public static IEnumerable <Note> QuantizeNotes(SongSimplification songSimplification, List <Bar> bars) { int standardTicksPerQuarterNote = 96; foreach (var n in songSimplification.Notes) { int i = 0; while (i < bars.Count && bars[i].TicksFromBeginningOfSong <= n.EndSinceBeginningOfSongInTicks) { i++; } yield return(QuantizeNote(n.Clone(), standardTicksPerQuarterNote, bars[i - 1].HasTriplets)); } }
/// <summary> /// We want to know if there are durations that are multiple of 3 /// in the bar. If the bar has triplets, then when we quantize the /// notes in the bar we must aproximate points to values that /// are multiple of 3 and not only powers of 2 /// </summary> /// <param name="song"></param> /// <param name="bar"></param> /// <returns></returns> public static bool HasBarTriplets(SongSimplification songSimplification, Bar bar) { int standardTicksPerQuarterNote = 96; var notes = GetNotesOfBar(bar, songSimplification); var lengthsOfTriplets = GetPossibleLengthsOfTriplets(standardTicksPerQuarterNote); int numberOfTriplets = 0; foreach (var n in notes) { foreach (var q in lengthsOfTriplets) { if (IsDurationEssentiallyTheSame(n, q)) { numberOfTriplets++; break; } } } return(numberOfTriplets * 2 > notes.Count); }
public static List <Note> GetNotesOfBar(Bar bar, SongSimplification songSimplification) { int standardTicksPerQuarterNote = 96; var retObj = new List <Note>(); foreach (var n in songSimplification.Notes) { int barLengthInTicks = bar.TimeSignature.Numerator * (int)standardTicksPerQuarterNote; var barStart = bar.TicksFromBeginningOfSong; var noteStart = n.StartSinceBeginningOfSongInTicks; var noteEnd = n.EndSinceBeginningOfSongInTicks; var barEnd = bar.TicksFromBeginningOfSong + barLengthInTicks; if (barEnd < noteStart || noteEnd <= barStart) { continue; } if (!retObj.Contains(n)) { retObj.Add(n); } } return(retObj.OrderBy(x => x.StartSinceBeginningOfSongInTicks).ToList()); }
public static SongSimplification GetSimplificationZeroOfSong(string base64encodedMidiFile) { var notesObj = new List <Note>(); var midiFile = MidiFile.Read(base64encodedMidiFile); long songDuration = GetSongDurationInTicks(base64encodedMidiFile); var isSustainPedalOn = false; var notesOnBecauseOfSustainPedal = new List <Note>(); var instrumentOfChannel = new byte[16]; short chunkNo = -1; foreach (TrackChunk chunk in midiFile.Chunks) { chunkNo++; var currentNotes = new List <Note>(); long currentTick = 0; foreach (MidiEvent eventito in chunk.Events) { currentTick += eventito.DeltaTime; if (eventito is ProgramChangeEvent) { var pg = eventito as ProgramChangeEvent; instrumentOfChannel[pg.Channel] = (byte)pg.ProgramNumber.valor; continue; } if (IsSustainPedalEventOn(eventito)) { isSustainPedalOn = true; continue; } if (IsSustainPedalEventOff(eventito)) { isSustainPedalOn = false; foreach (var n in notesOnBecauseOfSustainPedal) { ProcessNoteOff(n.Pitch, currentNotes, notesObj, currentTick, n.Instrument, (byte)chunkNo); } continue; } if (eventito is NoteOnEvent) { NoteOnEvent noteOnEvent = eventito as NoteOnEvent; if (noteOnEvent.Velocity > 0 || isSustainPedalOn == false) { ProcessNoteOn(noteOnEvent.NoteNumber, noteOnEvent.Velocity, currentNotes, notesObj, currentTick, instrumentOfChannel[noteOnEvent.Channel], IsPercussionEvent(eventito), (byte)chunkNo); } continue; } if (eventito is NoteOffEvent && isSustainPedalOn == false) { NoteOffEvent noteOffEvent = eventito as NoteOffEvent; ProcessNoteOff(noteOffEvent.NoteNumber, currentNotes, notesObj, currentTick, instrumentOfChannel[noteOffEvent.Channel], (byte)chunkNo); continue; } if (eventito is PitchBendEvent) { PitchBendEvent bendito = eventito as PitchBendEvent; foreach (var notita in currentNotes) { PitchBendEvent maldito = bendito.Clone() as PitchBendEvent; maldito.DeltaTime = currentTick; notita.PitchBending.Add(new PitchBendItem { Note = notita, Pitch = maldito.PitchValue, TicksSinceBeginningOfSong = maldito.DeltaTime }); } continue; } } } var retObj = new SongSimplification() { Notes = notesObj, SimplificationVersion = 0, NumberOfVoices = chunkNo }; return(retObj); }
/// <summary> /// Generates the list of bar entities of a midi file /// </summary> /// <param name="base64encodedMidiFile"></param> /// <returns></returns> public static List <Bar> GetBarsOfSong(string base64encodedMidiFile, SongSimplification songSimplification) { List <Bar> retObj = new List <Bar>(); int barNumber = 1; var ticksPerBeat = GetTicksPerBeatOfSong(base64encodedMidiFile); var songDurationInTicks = GetSongDurationInTicks(base64encodedMidiFile); var timeSignatureEvents = GetEventsOfType(base64encodedMidiFile, MidiEventType.TimeSignature); var setTempoEvents = GetEventsOfType(base64encodedMidiFile, MidiEventType.SetTempo); timeSignatureEvents = ConvertDeltaTimeToAccumulatedTime(timeSignatureEvents); var TempoEvents = QuantizeTempos(ConvertDeltaTimeToAccumulatedTime(setTempoEvents)); //status TimeSignatureEvent currentTimeSignature = new TimeSignatureEvent { Numerator = 4, Denominator = 4 }; if (timeSignatureEvents.Count > 0) { currentTimeSignature = (TimeSignatureEvent)timeSignatureEvents[0]; } int currentTempo = 500000; int timeSigIndex = 0; int tempoIndex = 0; long currentTick = 0; while (currentTick < songDurationInTicks) { if (TempoEvents.Count > 0) { currentTempo = (int)TempoEvents[tempoIndex].MicrosecondsPerQuarterNote; } long timeOfNextTimeSignatureEvent = songDurationInTicks; if (timeSignatureEvents.Count - 1 > timeSigIndex) { timeOfNextTimeSignatureEvent = timeSignatureEvents[timeSigIndex + 1].DeltaTime; } long timeOfNextSetTempoEvent = songDurationInTicks; if (TempoEvents.Count - 1 > tempoIndex) { timeOfNextSetTempoEvent = TempoEvents[tempoIndex + 1].DeltaTime; } long lastTickOfBarToBeAdded = currentTimeSignature.Numerator * ticksPerBeat + currentTick; while ((lastTickOfBarToBeAdded <= timeOfNextTimeSignatureEvent && lastTickOfBarToBeAdded <= timeOfNextSetTempoEvent) || (lastTickOfBarToBeAdded > songDurationInTicks)) { var timeSignature = new TimeSignature { Numerator = currentTimeSignature.Numerator, Denominator = currentTimeSignature.Denominator }; var bar = new Bar { BarNumber = barNumber++, TicksFromBeginningOfSong = currentTick, TimeSignature = timeSignature, TempoInMicrosecondsPerQuarterNote = currentTempo }; bar.HasTriplets = HasBarTriplets(songSimplification, bar); retObj.Add(bar); currentTick += currentTimeSignature.Numerator * ticksPerBeat; lastTickOfBarToBeAdded += currentTimeSignature.Numerator * ticksPerBeat; if (currentTick >= songDurationInTicks) { break; } } if (lastTickOfBarToBeAdded >= timeOfNextTimeSignatureEvent) { timeSigIndex++; } if (lastTickOfBarToBeAdded >= timeOfNextSetTempoEvent) { tempoIndex++; } } return(retObj); }
public async Task UpdateSongSimplificationAsync(SongSimplification simpl) { Context.SongSimplifications.Update(simpl); await Context.SaveChangesAsync(); }
/// <summary> /// Looks for unique chords and all their occurrences in a song simplification /// The key of the dictionary returned is the chord expressed as a sequence /// of pitches separated by commas (like "40,46,54"). The pitches are sorted /// </summary> /// <param name="simpl"></param> /// <returns></returns> public static Dictionary <string, List <ChordOccurrence> > GetChordsOfSimplification(SongSimplification simpl) { var durationOfHalfBeatInTicks = 48; var retObj = new Dictionary <string, List <ChordOccurrence> >(); // We create a dictionary where the keys are points it time // one for every half beat of the song and the values are the notes // played in that half beat // The assumption is that we don't have more than 2 chords in 1 beat // Since a note can last several beats, the same note and // the same chord can be in many entries // of the dictionary var beatNotes = new Dictionary <long, List <Note> >(); foreach (Note n in simpl.Notes) { if (n.IsPercussion) { continue; } var startBeat = n.StartSinceBeginningOfSongInTicks / durationOfHalfBeatInTicks; var endBeat = n.EndSinceBeginningOfSongInTicks / durationOfHalfBeatInTicks; for (var i = startBeat; i <= endBeat; i++) { if (!beatNotes.ContainsKey(i)) { beatNotes[i] = new List <Note>(); } beatNotes[i].Add(n); } } // Now we look at the notes played in each half beat. // We group the notes according to their start and stop times // The notes that start and stop simultatneously are // candidates for a chord foreach (var slice in beatNotes.Keys) { var sliceNotes = beatNotes[slice]; if (sliceNotes.Count < 2) { continue; } var possibleChords = new List <List <Note> >(); foreach (var n in sliceNotes) { var isNoteProcessed = false; foreach (var possibleChord in possibleChords) { if (IsNoteSimultaneousWithGroup(possibleChord, n)) { possibleChord.Add(n); isNoteProcessed = true; } } if (!isNoteProcessed) { var possibleChord = new List <Note>(); possibleChord.Add(n); possibleChords.Add(possibleChord); } } // We have now in possibleChords a list of groups of notes // We select the ones that have at least 2 notes if (possibleChords.Count > 0) { foreach (var possibleChord in possibleChords) { if (possibleChord.Count < 2 || !NotesGenerateHarmony(possibleChord)) { continue; } var thisChord = new Chord(possibleChord); if (!retObj.ContainsKey(thisChord.PitchesAsString)) { retObj[thisChord.PitchesAsString] = new List <ChordOccurrence>(); } var chordOccurrence = new ChordOccurrence { StartTick = possibleChord.FirstOrDefault().StartSinceBeginningOfSongInTicks, EndTick = possibleChord.FirstOrDefault().EndSinceBeginningOfSongInTicks, SongSimplificationId = simpl.Id }; if (!IsOccurrenceAlreadyInList(retObj[thisChord.PitchesAsString], chordOccurrence)) { retObj[thisChord.PitchesAsString].Add(chordOccurrence); } } } } return(retObj); }