├── resources ├── artistsfile ├── lyrics_seed ├── stopwords ├── hdf-java.jar ├── externalDeps │ ├── jEN.jar │ └── jfugue-5.0.3.jar ├── crawledsheets │ └── RabitMinesGameMusic.png └── non_lyrics_words ├── setEnviroment.sh ├── shippable.yml ├── src ├── test │ ├── testdata │ │ ├── midi │ │ │ ├── test.mid │ │ │ └── Bach_SMD.mid │ │ ├── mp3 │ │ │ ├── Bach_SMD.mp3 │ │ │ └── stairway_to_heaven.mp3 │ │ ├── research │ │ │ └── test.h5 │ │ ├── musicxml │ │ │ ├── attributesTestData.xml │ │ │ └── chord.xml │ │ └── lyrics │ │ │ ├── stairway_to_heaven │ │ │ └── barbie_girl │ └── java │ │ ├── interactive │ │ └── Modulo7CLITests.java │ │ ├── enginetests │ │ └── CacheTest.java │ │ ├── parsertests │ │ ├── AudiverisMusicSheetXMLTest.java │ │ ├── MP3Test.java │ │ ├── MidiTest.java │ │ └── ComparisonsTest.java │ │ ├── BasicTests.java │ │ ├── nlptests │ │ └── NLPUtilsTest.java │ │ └── musicstatmodelstests │ │ └── MaxMelodicRepeatingFactorTest.java └── main │ ├── java │ └── com │ │ └── modulo7 │ │ ├── playback │ │ ├── AbstractPlayBack.java │ │ ├── MP3PlayBack.java │ │ ├── MidiPlayBack.java │ │ ├── MusicXMLPlayback.java │ │ └── SheetMusicPlayBack.java │ │ ├── musicstatmodels │ │ ├── musictheorymodels │ │ │ ├── IntervalType.java │ │ │ ├── IntervalQuality.java │ │ │ └── IntervalQuantity.java │ │ ├── representation │ │ │ ├── metadata │ │ │ │ ├── Clef.java │ │ │ │ ├── ScaleDegree.java │ │ │ │ └── ScaleType.java │ │ │ ├── buildingblocks │ │ │ │ ├── NoteType.java │ │ │ │ ├── ChordProgression.java │ │ │ │ ├── Accidental.java │ │ │ │ └── NoteDuration.java │ │ │ └── monophonic │ │ │ │ ├── VoiceTag.java │ │ │ │ └── VoiceClass.java │ │ ├── statistics │ │ │ ├── NumVoices.java │ │ │ ├── AveragePitchDuration.java │ │ │ ├── LyricalSemanticIntent.java │ │ │ ├── LongestChordProgression.java │ │ │ ├── SadnessIndex.java │ │ │ ├── HappinessIndex.java │ │ │ ├── MostFrequentScaleDegree.java │ │ │ ├── PowerIndex.java │ │ │ └── MostFrequentPitch.java │ │ ├── similarity │ │ │ ├── songsimilarity │ │ │ │ ├── UkkonnenSongSimilarity.java │ │ │ │ ├── SCMNGramSongSimilarity.java │ │ │ │ ├── GrossSongContourSilimarity.java │ │ │ │ ├── CountDistanceSongSimilarity.java │ │ │ │ ├── MaxMelodicEditDistanceSimilarity.java │ │ │ │ ├── WeightedTonalHistogramSimilarity.java │ │ │ │ └── TonalHistogramSimilarity.java │ │ │ ├── lyricssimilarity │ │ │ │ └── LyricsTFIDFSimilarity.java │ │ │ ├── contoursimilarity │ │ │ │ ├── SteinbeckContourSimililarity.java │ │ │ │ ├── NaturalContourSimilarity.java │ │ │ │ └── MullensefsteinContourSimilarity.java │ │ │ ├── voicesimilarity │ │ │ │ ├── VoiceTonalHistogramSimilarity.java │ │ │ │ ├── RawMelodicEditDistanceSimilarity.java │ │ │ │ ├── GrossContourSimilarity.java │ │ │ │ ├── UkkonnenSimilarity.java │ │ │ │ ├── CountDistanceSimilarity.java │ │ │ │ └── SCMNGramSimilarity.java │ │ │ └── genericsimilarity │ │ │ │ ├── GeneralMaximalVoiceSimilarity.java │ │ │ │ └── SongContourSimilarity.java │ │ ├── criteria │ │ │ ├── PolyphonyCriteria.java │ │ │ ├── ScaleTypeCriteria.java │ │ │ ├── STABVoiceClassificationCriteria.java │ │ │ ├── KeySignatureEqualityCriteria.java │ │ │ ├── TimeSignatureEqualityCriteria.java │ │ │ └── PositiveLyricsIntentCriteria.java │ │ ├── vectorspacemodels │ │ │ ├── vectorspacerepresentations │ │ │ │ ├── songvectors │ │ │ │ │ ├── ContourGradientVector.java │ │ │ │ │ ├── PitchVector.java │ │ │ │ │ ├── PitchDurationHistogram.java │ │ │ │ │ └── TonalHistogram.java │ │ │ │ └── voicevectors │ │ │ │ │ ├── VoiceRawPitchVector.java │ │ │ │ │ └── VoiceIntervalPitchVector.java │ │ │ ├── datastructures │ │ │ │ ├── VoicePitchList.java │ │ │ │ ├── PitchDurationHistogramData.java │ │ │ │ └── VoiceIntervalPitchList.java │ │ │ └── contour │ │ │ │ ├── ContourSongRep.java │ │ │ │ └── voicecontour │ │ │ │ ├── GrossContour.java │ │ │ │ ├── MullensiefenContour.java │ │ │ │ └── NaturalContour.java │ │ ├── misc │ │ │ └── TonalityAlignment.java │ │ └── preprocessing │ │ │ ├── VoiceToMelodyConversion.java │ │ │ └── TonalityAlignment.java │ │ ├── common │ │ ├── exceptions │ │ │ ├── Modulo7ParseException.java │ │ │ ├── Modulo7IndexingDirError.java │ │ │ ├── Modulo7InvalidArgsException.java │ │ │ ├── Modulo7BadChordException.java │ │ │ ├── Modulo7MalformedM7SQLQuery.java │ │ │ ├── Modulo7BadKeyException.java │ │ │ ├── Modulo7InvalidVoiceInstantSizeException.java │ │ │ ├── Modulo7InvalidFileOperationException.java │ │ │ ├── Modulo7QueryProcessingException.java │ │ │ ├── Modulo7NoSuchSongSimilarityMeasureException.java │ │ │ ├── Modulo7NoSuchVoiceSimilarityMeasureException.java │ │ │ ├── Modulo7DataBaseNotSerializedException.java │ │ │ ├── Modulo7BaseException.java │ │ │ ├── Modulo7WrongNoteType.java │ │ │ ├── Modulo7BadNoteException.java │ │ │ ├── Modulo7BadIntervalException.java │ │ │ ├── Modulo7VectorSizeMismatchException.java │ │ │ ├── Modulo7BadAccidentalException.java │ │ │ ├── Modulo7InvalidMusicXMLFile.java │ │ │ ├── Modulo7FileFormatException.java │ │ │ ├── Modulo7InvalidCircleOfFifthsDistance.java │ │ │ ├── Modulo7NoSuchFileOrDirectoryException.java │ │ │ └── Modulo7InvalidOctaveRangeException.java │ │ ├── interfaces │ │ │ ├── AbstractLyricsSimilarity.java │ │ │ ├── AbstractStatistic.java │ │ │ ├── AbstractAnalyzer.java │ │ │ ├── AbstractVoiceSimilarity.java │ │ │ ├── AbstractStringContour.java │ │ │ ├── AbstractSongSimilarity.java │ │ │ ├── AbstractCriteria.java │ │ │ ├── AbstractContour.java │ │ │ ├── AbstractSongVector.java │ │ │ └── AbstractVoiceVector.java │ │ └── utils │ │ │ ├── MusicSources.java │ │ │ └── HDFSUtils.java │ │ ├── pureresearch │ │ ├── metadataestimation │ │ │ ├── bagofwordslyricssim │ │ │ │ ├── BOWSimilarityChoices.java │ │ │ │ ├── CosineSimilarity.java │ │ │ │ ├── DiceSimilarity.java │ │ │ │ ├── OverLapSimilarity.java │ │ │ │ ├── Modulo7BM25Similarity.java │ │ │ │ ├── JacardSimilarity.java │ │ │ │ └── BOWSimilarity.java │ │ │ ├── PrecRec.java │ │ │ ├── ROCDataPoint.java │ │ │ ├── GenreLabels.java │ │ │ ├── genreestimation │ │ │ │ ├── GenreEstimation.java │ │ │ │ ├── NaiveGenreEstimation.java │ │ │ │ └── WeightedGenreEstimation.java │ │ │ └── tagestimation │ │ │ │ ├── NaiveTagEstimation.java │ │ │ │ ├── MaxFrequencyTagEstimation.java │ │ │ │ └── WeightedTagEstimation.java │ │ ├── lastfm │ │ │ ├── SongBagLyricsComparator.java │ │ │ ├── SongBagLyricsGenreComparator.java │ │ │ ├── SongSimilarityElement.java │ │ │ └── SongBagLyricsGenreMap.java │ │ └── musicmatch │ │ │ ├── LyricsBagOfWordsFormat.java │ │ │ └── BagOfWordsDataElement.java │ │ ├── engine │ │ ├── cache │ │ │ ├── Modulo7CustomQueryCacheObject.java │ │ │ ├── Modulo7SimilarityResultCacheObject.java │ │ │ ├── Modulo7CacheObject.java │ │ │ └── Modulo7Cache.java │ │ └── processing │ │ │ ├── TonalAlignmentEngine.java │ │ │ └── PlaybackEngine.java │ │ ├── fun │ │ └── HelloWorldGUI.java │ │ ├── nlp │ │ └── models │ │ │ └── SentimentModel.java │ │ ├── acoustics │ │ └── EchoNestKeySignatureEstimator.java │ │ ├── modulo7SQL │ │ └── Modulo7QueryComponents.java │ │ ├── othersources │ │ └── NoteAndIsChordDual.java │ │ └── cli │ │ └── Modulo7CLIChoice.java │ ├── include │ └── HoughTransform.hpp │ ├── antlr │ ├── Modulo7SQLBase.tokens │ ├── Modulo7SQLBase.g4 │ └── Modulo7SQL.g4 │ └── config │ └── cache.ccf ├── hdf5script.sh ├── .gitignore ├── modulo7log4.properties └── doc ├── similarity_description └── algebra_description /resources/artistsfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setEnviroment.sh: -------------------------------------------------------------------------------- 1 | export MODULO7_ROOT=`pwd` -------------------------------------------------------------------------------- /resources/lyrics_seed: -------------------------------------------------------------------------------- 1 | http://www.azlyrics.com/ -------------------------------------------------------------------------------- /resources/stopwords: -------------------------------------------------------------------------------- 1 | and 2 | or 3 | to 4 | if 5 | for 6 | these 7 | here 8 | us -------------------------------------------------------------------------------- /resources/hdf-java.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/resources/hdf-java.jar -------------------------------------------------------------------------------- /shippable.yml: -------------------------------------------------------------------------------- 1 | script: 2 | - export PATH=$PATH:/gradle-2.5/bin && cd Modulo7 && gradle build 3 | -------------------------------------------------------------------------------- /resources/externalDeps/jEN.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/resources/externalDeps/jEN.jar -------------------------------------------------------------------------------- /src/test/testdata/midi/test.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/src/test/testdata/midi/test.mid -------------------------------------------------------------------------------- /src/test/testdata/midi/Bach_SMD.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/src/test/testdata/midi/Bach_SMD.mid -------------------------------------------------------------------------------- /src/test/testdata/mp3/Bach_SMD.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/src/test/testdata/mp3/Bach_SMD.mp3 -------------------------------------------------------------------------------- /src/test/testdata/research/test.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/src/test/testdata/research/test.h5 -------------------------------------------------------------------------------- /hdf5script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export HDFVIEW_HOME="/home/asanyal/Downloads/hdf-java-2.11.0/" 4 | export JAVAPATH=/usr/bin 5 | 6 | -------------------------------------------------------------------------------- /resources/externalDeps/jfugue-5.0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/resources/externalDeps/jfugue-5.0.3.jar -------------------------------------------------------------------------------- /src/test/testdata/mp3/stairway_to_heaven.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/src/test/testdata/mp3/stairway_to_heaven.mp3 -------------------------------------------------------------------------------- /resources/crawledsheets/RabitMinesGameMusic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khalian/Modulo7/HEAD/resources/crawledsheets/RabitMinesGameMusic.png -------------------------------------------------------------------------------- /src/main/java/com/modulo7/playback/AbstractPlayBack.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.playback; 2 | 3 | /** 4 | * Created by asanyal on 10/22/15. 5 | * 6 | * Playbacks for different music sources 7 | */ 8 | public interface AbstractPlayBack { 9 | 10 | public void play(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/musictheorymodels/IntervalType.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.musictheorymodels; 2 | 3 | /** 4 | * Created by asanyal on 8/20/15. 5 | * 6 | * Whether the interval type is ascending or descending 7 | */ 8 | public enum IntervalType { 9 | ASCENDING, 10 | DESCENDING, 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/musictheorymodels/IntervalQuality.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.musictheorymodels; 2 | 3 | /** 4 | * Created by asanyal on 8/20/15. 5 | * 6 | * An enum which denotes the type of interval quality 7 | */ 8 | public enum IntervalQuality { 9 | MINOR, 10 | MAJOR, 11 | PERFECT, 12 | AUGMENTED, 13 | DIMINISHED 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/metadata/Clef.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.metadata; 2 | 3 | /** 4 | * Created by asanyal on 9/18/15. 5 | * 6 | * Clef information about the voice. A voice sticks to one clef 7 | * a voice can be more than one 8 | */ 9 | public enum Clef { 10 | Bass, 11 | Treble, 12 | Unknown, 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7ParseException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/20/15. 5 | * 6 | * Wrapper on top of lucene parse exception 7 | */ 8 | public class Modulo7ParseException extends Modulo7BaseException { 9 | 10 | public Modulo7ParseException(Throwable cause) { 11 | super(cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/interactive/Modulo7CLITests.java: -------------------------------------------------------------------------------- 1 | package interactive; 2 | 3 | import com.modulo7.cli.Modulo7CLI; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by asanyal on 10/8/15. 8 | * 9 | * Test cases for Modulo7 CLI 10 | */ 11 | public class Modulo7CLITests { 12 | 13 | @Test 14 | public void modulo7CLITest() { 15 | Modulo7CLI cli = new Modulo7CLI(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractLyricsSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.nlp.lyrics.Lyrics; 4 | 5 | /** 6 | * Created by asanyal on 10/2/15. 7 | * 8 | * An interface for lyrics similarity 9 | */ 10 | public interface AbstractLyricsSimilarity { 11 | 12 | public double getSimilarity(final Lyrics thisLyrics, final Lyrics thatLyrics); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7IndexingDirError.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/13/15. 5 | * 6 | * Exception stating user is encountering an indexing error 7 | */ 8 | public class Modulo7IndexingDirError extends Modulo7BaseException { 9 | 10 | public Modulo7IndexingDirError(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidArgsException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BaseException; 4 | 5 | /** 6 | * Created by asanyal on 7/19/2015. 7 | */ 8 | public class Modulo7InvalidArgsException extends Modulo7BaseException { 9 | public Modulo7InvalidArgsException(final String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BadChordException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/8/15. 5 | * 6 | * This exception is thrown when a bad chord construction takes place in modulo7 7 | */ 8 | public class Modulo7BadChordException extends Modulo7BaseException { 9 | public Modulo7BadChordException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractStatistic.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | 5 | /** 6 | * Created by asanyal on 7/25/2015. 7 | * 8 | * Base class to acquire a particular statistic on a song 9 | * 10 | */ 11 | public interface AbstractStatistic { 12 | 13 | public T getStatistic(final Song song); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7MalformedM7SQLQuery.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/16/15. 5 | * 6 | * This exception is thrown when a malformed query is given to the m7 parser 7 | */ 8 | public class Modulo7MalformedM7SQLQuery extends Modulo7BaseException { 9 | 10 | public Modulo7MalformedM7SQLQuery(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/BOWSimilarityChoices.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | /** 4 | * Created by asanyal on 12/19/15. 5 | * 6 | * Bag of words similarity measure choices 7 | */ 8 | public enum BOWSimilarityChoices { 9 | COSINE_SIMILARITY, 10 | DICE_SIMILARITY, 11 | JACARD_SIMILARITY, 12 | OVERLAP_SIMILARITY 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BadKeyException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 7/25/2015. 5 | */ 6 | public class Modulo7BadKeyException extends Modulo7BaseException { 7 | public Modulo7BadKeyException(final String message) { 8 | super(message); 9 | } 10 | 11 | public Modulo7BadKeyException(final Throwable cause) { 12 | super(cause); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /resources/non_lyrics_words: -------------------------------------------------------------------------------- 1 | A 2 | B 3 | C 4 | D 5 | E 6 | F 7 | G 8 | H 9 | I 10 | J 11 | K 12 | L 13 | M 14 | N 15 | O 16 | P 17 | Q 18 | R 19 | S 20 | T 21 | U 22 | V 23 | W 24 | X 25 | Y 26 | Z 27 | # 28 | Search 29 | MP3 30 | Email 31 | Print 32 | Submit 33 | Corrections 34 | Visit 35 | lyrics 36 | A-Z 37 | request 38 | submit 39 | soundtracks 40 | music 41 | videos 42 | facebook 43 | links 44 | advertise 45 | privacy 46 | policy 47 | contact 48 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidVoiceInstantSizeException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BaseException; 4 | 5 | /** 6 | * Created by asanyal on 7/18/2015. 7 | */ 8 | public class Modulo7InvalidVoiceInstantSizeException extends Modulo7BaseException { 9 | public Modulo7InvalidVoiceInstantSizeException(final String message) { 10 | super (message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidFileOperationException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/16/15. 5 | * 6 | * Exception to be used when there is an issue while modulo7 operates with a file 7 | */ 8 | public class Modulo7InvalidFileOperationException extends Modulo7BaseException { 9 | 10 | public Modulo7InvalidFileOperationException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7QueryProcessingException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/21/15. 5 | * 6 | * This exception is thrown whenever query processing goes through 7 | * an error in the modulo7 engine 8 | */ 9 | public class Modulo7QueryProcessingException extends Modulo7BaseException { 10 | public Modulo7QueryProcessingException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7NoSuchSongSimilarityMeasureException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/24/15. 5 | * 6 | * Exception which states no such similarity measure was found 7 | */ 8 | public class Modulo7NoSuchSongSimilarityMeasureException extends Modulo7BaseException { 9 | 10 | public Modulo7NoSuchSongSimilarityMeasureException(final String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7NoSuchVoiceSimilarityMeasureException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 10/16/15. 5 | * 6 | * When you have no such voice similarity measure in the list of implemented measures 7 | */ 8 | public class Modulo7NoSuchVoiceSimilarityMeasureException extends Modulo7BaseException { 9 | public Modulo7NoSuchVoiceSimilarityMeasureException(String s) { 10 | super(s); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractAnalyzer.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | 5 | /** 6 | * Created by asanyal on 8/5/2015. 7 | * 8 | * An abstract analyzer for acoustic sources 9 | * All new acoustic sources must implement this interface 10 | */ 11 | public interface AbstractAnalyzer { 12 | 13 | // Acquire the modulo7Song representation 14 | public Song getSongRepresentation(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractVoiceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 4 | 5 | /** 6 | * Created by asanyal on 9/18/15. 7 | * 8 | * A similarity metric between two voices 9 | */ 10 | public interface AbstractVoiceSimilarity { 11 | 12 | // Acquire the similarity between any two modulo7 voice representations 13 | public double getSimilarity(final Voice first, final Voice second); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7DataBaseNotSerializedException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 9/8/15. 5 | * 6 | * Exception dictating the fact that the modulo7 database has not been serialized yet 7 | * and the operation being performed in code is invalid 8 | */ 9 | public class Modulo7DataBaseNotSerializedException extends Modulo7BaseException { 10 | public Modulo7DataBaseNotSerializedException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/buildingblocks/NoteType.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.buildingblocks; 2 | 3 | /** 4 | * Created by asanyal on 6/16/2015. 5 | * 6 | * Expressing the type of a note of a line within a song 7 | * 8 | * Two types exist, either a single frequency is played at that moment 9 | * or an set of notes being stacked on top of each other (called a chord) 10 | */ 11 | public enum NoteType { 12 | MELODIC_NOTE, 13 | CHORD, 14 | REST, 15 | UNKNOWN 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractStringContour.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 4 | 5 | /** 6 | * Created by asanyal on 10/4/15. 7 | * 8 | * Text represenatations of contour 9 | */ 10 | public interface AbstractStringContour { 11 | 12 | /** 13 | * Gets the string representation of contour 14 | * @param voice 15 | * @return 16 | */ 17 | public String getContourRepresentaionOfVoice(final Voice voice); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/lastfm/SongBagLyricsComparator.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.lastfm; 2 | 3 | import java.util.Comparator; 4 | 5 | /** 6 | * Created by asanyal on 12/19/15. 7 | * 8 | * Compatator for song bag lyrics 9 | */ 10 | public class SongBagLyricsComparator implements Comparator { 11 | 12 | @Override 13 | public int compare(SongBagLyricsAndMetadata thisBag, SongBagLyricsAndMetadata thatBag) { 14 | return thisBag.getTrackID().compareTo(thatBag.getTrackID()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Package Files # 2 | *.war 3 | *.ear 4 | *.gz 5 | 6 | # Folders 7 | /bin/* 8 | /target/* 9 | /build/* 10 | /vs/* 11 | /gradle/* 12 | /default-lyrics-index-dir/* 13 | /src/test/researchData/* 14 | /jcs_swap/* 15 | 16 | # Normal Files 17 | .settings 18 | .idea 19 | .gradle 20 | .project 21 | .classpath 22 | *.class 23 | *.iml 24 | *.log 25 | *.m7 26 | *.pdf 27 | *.aux 28 | *.ipr 29 | *.iws 30 | *.jpg 31 | *.gif 32 | *.png 33 | ~* 34 | *.nsf 35 | *.lyrics 36 | *.out 37 | *.tex.bak 38 | *.sln* 39 | *.vcproj* 40 | *.vcxproj* 41 | *.ser* 42 | *.csv* 43 | *.tag* 44 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BaseException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 6/29/2015. 5 | */ 6 | public class Modulo7BaseException extends Exception { 7 | public Modulo7BaseException (final String message) { 8 | super (message); 9 | } 10 | 11 | public Modulo7BaseException (final Throwable cause) { 12 | super (cause); 13 | } 14 | 15 | public Modulo7BaseException (final String message, final Throwable cause) { 16 | super (message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/lastfm/SongBagLyricsGenreComparator.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.lastfm; 2 | 3 | import java.util.Comparator; 4 | 5 | /** 6 | * Created by asanyal on 12/22/15. 7 | * 8 | * Compares two genre mapped lyrics bag objects 9 | */ 10 | public class SongBagLyricsGenreComparator implements Comparator { 11 | @Override 12 | public int compare(final SongBagLyricsGenreMap thisBag, final SongBagLyricsGenreMap thatBag) { 13 | return thisBag.getTrackID().compareTo(thatBag.getTrackID()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractSongSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | 5 | /** 6 | * Created by asanyal on 7/25/2015. 7 | * 8 | * The base class which denotes an extensible similarity 9 | * measures are to be used are to be performed 10 | * 11 | */ 12 | public interface AbstractSongSimilarity { 13 | 14 | // Acquire the similarity between any two modulo7 song representations 15 | public double getSimilarity(final Song first, final Song second); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/metadata/ScaleDegree.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.metadata; 2 | 3 | /** 4 | * Created by asanyal on 10/2/15. 5 | * 6 | * Scale Degree is used to denote the position on a given scale 7 | * They have special names with a special role on each scale 8 | * 9 | * TODO : Complete scale degree analysis 10 | */ 11 | public enum ScaleDegree { 12 | 13 | TONIC, 14 | SUPERTONIC, 15 | MEDIANT, 16 | SUBDOMINANT, 17 | DOMINANT, 18 | SUBMEDIANT, 19 | SUBTONIC, 20 | LEADING_TONE 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/NumVoices.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractStatistic; 4 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 5 | 6 | /** 7 | * Created by asanyal on 9/26/15. 8 | * 9 | * Simple criteria which returns the number of voices in the song 10 | */ 11 | public class NumVoices implements AbstractStatistic { 12 | @Override 13 | public Double getStatistic(final Song song) { 14 | return (double) song.getNumVoices(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7WrongNoteType.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/21/15. 5 | * 6 | * Exception denoting the wrong type of note 7 | */ 8 | public class Modulo7WrongNoteType extends Modulo7BaseException { 9 | public Modulo7WrongNoteType(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7WrongNoteType(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7WrongNoteType(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | 5 | /** 6 | * Created by asanyal on 8/29/15. 7 | * 8 | * Criteria's are predicates about a particular music theoretic assertion 9 | * that a song satisfies or not 10 | */ 11 | public interface AbstractCriteria { 12 | 13 | /** 14 | * Returns whether the song satisfies a particular criteria or not 15 | * 16 | * @param song 17 | * @return 18 | */ 19 | public boolean getCriteriaEvaluation(final Song song); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/cache/Modulo7CustomQueryCacheObject.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.cache; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * Created by asanyal on 11/2/15. 7 | * 8 | * A cached modulo7 object, i.e a custom query and relevant results to that query 9 | */ 10 | public class Modulo7CustomQueryCacheObject extends Modulo7CacheObject> { 11 | 12 | /** 13 | * Basic constructor of the cache object 14 | * 15 | * @param queryResults 16 | */ 17 | public Modulo7CustomQueryCacheObject(final Set queryResults) { 18 | super(queryResults); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BadNoteException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/17/15. s 5 | * 6 | * Exception which states that the exception is bad 7 | */ 8 | public class Modulo7BadNoteException extends Modulo7BaseException { 9 | public Modulo7BadNoteException(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7BadNoteException(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7BadNoteException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/cache/Modulo7SimilarityResultCacheObject.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.cache; 2 | 3 | import java.util.LinkedHashMap; 4 | 5 | /** 6 | * Created by asanyal on 11/6/15. 7 | * 8 | * A similarity measure result cache object 9 | */ 10 | public class Modulo7SimilarityResultCacheObject extends Modulo7CacheObject> { 11 | /** 12 | * Basic constructor of the cache object 13 | * 14 | * @param queryResults 15 | */ 16 | public Modulo7SimilarityResultCacheObject(LinkedHashMap queryResults) { 17 | super(queryResults); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BadIntervalException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/20/15. 5 | * 6 | * Exception stating that bad interval is encountered 7 | */ 8 | public class Modulo7BadIntervalException extends Modulo7BaseException { 9 | public Modulo7BadIntervalException(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7BadIntervalException(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7BadIntervalException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7VectorSizeMismatchException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/30/15. 5 | * 6 | * Exception detailing vector sizes are mismatched 7 | */ 8 | public class Modulo7VectorSizeMismatchException extends Modulo7BaseException { 9 | 10 | public Modulo7VectorSizeMismatchException(String message) { 11 | super(message); 12 | } 13 | 14 | public Modulo7VectorSizeMismatchException(int size1, int size2) { 15 | super("The vectors need to be of equal size. In this case First Vector Size :" + size1 + " Second Vector Size :" + size2); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7BadAccidentalException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/17/15. 5 | * 6 | * A exception which states that the bad exception has been thrown 7 | */ 8 | public class Modulo7BadAccidentalException extends Modulo7BaseException { 9 | public Modulo7BadAccidentalException(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7BadAccidentalException(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7BadAccidentalException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/PrecRec.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation; 2 | 3 | /** 4 | * Created by asanyal on 12/23/15. 5 | * 6 | * Precision and recall bundled into one class 7 | */ 8 | public class PrecRec { 9 | 10 | private double precision; 11 | 12 | private double recall; 13 | 14 | public PrecRec(final double precision, final double recall) { 15 | this.precision = precision; 16 | this.recall = recall; 17 | } 18 | 19 | public double getPrecision() { 20 | return precision; 21 | } 22 | 23 | public double getRecall() { 24 | return recall; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidMusicXMLFile.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 7/23/2015. 5 | * 6 | * Exception indicating that the modulo7 file input is of invalid music 7 | * xml format 8 | */ 9 | public class Modulo7InvalidMusicXMLFile extends Modulo7BaseException { 10 | public Modulo7InvalidMusicXMLFile(final String message) { 11 | super(message); 12 | } 13 | 14 | public Modulo7InvalidMusicXMLFile(final Throwable cause) { 15 | super(cause); 16 | } 17 | 18 | public Modulo7InvalidMusicXMLFile(final String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7FileFormatException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 6/29/2015. 5 | * 6 | * To be thrown by Modulo7 code when a wrong file format is encountered 7 | * in method 8 | */ 9 | public class Modulo7FileFormatException extends Modulo7BaseException { 10 | public Modulo7FileFormatException(final String message) { 11 | super (message); 12 | } 13 | 14 | public Modulo7FileFormatException(final Throwable cause) { 15 | super (cause); 16 | } 17 | 18 | public Modulo7FileFormatException(final String message, Throwable cause) { 19 | super (message, cause); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidCircleOfFifthsDistance.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/9/15. 5 | * 6 | * This exception is thrown if any reference on the circle of fifths i 7 | */ 8 | public class Modulo7InvalidCircleOfFifthsDistance extends Modulo7BaseException { 9 | public Modulo7InvalidCircleOfFifthsDistance(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7InvalidCircleOfFifthsDistance(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7InvalidCircleOfFifthsDistance(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7NoSuchFileOrDirectoryException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 8/6/2015. 5 | * 6 | * An exception from modulo7 which states no such file was found 7 | */ 8 | public class Modulo7NoSuchFileOrDirectoryException extends Modulo7BaseException { 9 | public Modulo7NoSuchFileOrDirectoryException(String message) { 10 | super(message); 11 | } 12 | 13 | public Modulo7NoSuchFileOrDirectoryException(Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public Modulo7NoSuchFileOrDirectoryException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/CosineSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by asanyal on 12/19/15. 7 | */ 8 | public class CosineSimilarity extends BOWSimilarity { 9 | 10 | /** 11 | * Base constructor 12 | * 13 | * @param bog1 14 | * @param bog2 15 | */ 16 | public CosineSimilarity(Map bog1, Map bog2) { 17 | super(bog1, bog2); 18 | } 19 | 20 | @Override 21 | public double getSimVal() { 22 | return (v1.dotProduct(v2)) / (v1.getNorm() * v2.getNorm()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractContour.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 4 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 5 | 6 | import java.util.LinkedHashMap; 7 | 8 | /** 9 | * Created by asanyal on 9/6/15. 10 | * 11 | * A contour is a representation of a shape of the melody. Modulo7 represents it as a reimagined voice 12 | * 13 | * In order words certain operations are performed on the voice to reduce the number 14 | */ 15 | public interface AbstractContour { 16 | 17 | public LinkedHashMap getContourRepresentaionOfVoice(final Voice voice); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/DiceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by asanyal on 12/19/15. 7 | */ 8 | public class DiceSimilarity extends BOWSimilarity { 9 | /** 10 | * Base constructor 11 | * 12 | * @param bog1 13 | * @param bog2 14 | */ 15 | public DiceSimilarity(final Map bog1, final Map bog2) { 16 | super(bog1, bog2); 17 | } 18 | 19 | @Override 20 | public double getSimVal() { 21 | return 2 * v1.dotProduct(v2) / (getVectorSum(v1) + getVectorSum(v2)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/cache/Modulo7CacheObject.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.cache; 2 | 3 | /** 4 | * Created by asanyal on 11/6/15. 5 | * 6 | * A modulo7 cache object 7 | */ 8 | public class Modulo7CacheObject { 9 | 10 | // Set of songs returned in a total order 11 | private T queryResults; 12 | 13 | /** 14 | * Basic constructor of the cache object 15 | * 16 | * @param queryResults 17 | */ 18 | public Modulo7CacheObject(final T queryResults) { 19 | this.queryResults = queryResults; 20 | } 21 | 22 | /** 23 | * Get the query results 24 | * @return 25 | */ 26 | public T getQueryResults() { 27 | return queryResults; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/UkkonnenSongSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.GeneralMaximalVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.voicesimilarity.UkkonnenSimilarity; 5 | 6 | /** 7 | * Created by asanyal on 10/13/15. 8 | * 9 | * Ukkonnen similarity measure 10 | */ 11 | public class UkkonnenSongSimilarity extends GeneralMaximalVoiceSimilarity { 12 | /** 13 | * Basic constructor for UkkonnenSongSimilarity 14 | */ 15 | public UkkonnenSongSimilarity() { 16 | super(new UkkonnenSimilarity()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/OverLapSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by asanyal on 12/19/15. 7 | */ 8 | public class OverLapSimilarity extends BOWSimilarity { 9 | /** 10 | * Base constructor 11 | * 12 | * @param bog1 13 | * @param bog2 14 | */ 15 | public OverLapSimilarity(final Map bog1, final Map bog2) { 16 | super(bog1, bog2); 17 | } 18 | 19 | @Override 20 | public double getSimVal() { 21 | return v1.dotProduct(v2) / Math.min(getVectorSum(v1), getVectorSum(v2)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/PolyphonyCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.modulo7.common.interfaces.AbstractCriteria; 4 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 5 | 6 | /** 7 | * Created by asanyal on 9/16/15lo 8 | * 9 | * A very simple criteria to judge whether a song is polyphonic or monophoic 10 | * This criteria is a basis on top of which many criteria is built on 11 | * 12 | * It returns whether the song is polyphonic or not 13 | */ 14 | public class PolyphonyCriteria implements AbstractCriteria { 15 | @Override 16 | public boolean getCriteriaEvaluation(final Song song) { 17 | return song.getNumVoices() != 1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/SCMNGramSongSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.GeneralMaximalVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.voicesimilarity.SCMNGramSimilarity; 5 | 6 | /** 7 | * Created by asanyal on 10/13/15. 8 | * 9 | * Song similarity version of scn n gram similarity 10 | */ 11 | public class SCMNGramSongSimilarity extends GeneralMaximalVoiceSimilarity { 12 | 13 | /** 14 | * Basic constructor for SCMNGramSongSimilarity 15 | */ 16 | public SCMNGramSongSimilarity() { 17 | super(new SCMNGramSimilarity()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractSongVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | 5 | /** 6 | * Created by asanyal on 9/4/15. 7 | * 8 | * An abstraction of the vector space model in Modulo7's vector 9 | * space model definitions 10 | */ 11 | public interface AbstractSongVector { 12 | 13 | /** 14 | * Computes the vector representation from the elements in 15 | * the song representation of Modulo7 16 | */ 17 | public void computeVectorRepresentation(final Song song); 18 | 19 | /** 20 | * Gets the internal representation of the vector 21 | * @return 22 | */ 23 | public T getInternalRepresentation(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/Modulo7BM25Similarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import org.apache.lucene.search.similarities.BM25Similarity; 4 | 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | /** 9 | * Created by asanyal on 12/12/15. 10 | * 11 | * Using the BM25 similarity measure on modulo7 12 | */ 13 | public class Modulo7BM25Similarity extends BOWSimilarity { 14 | 15 | public Modulo7BM25Similarity(final Map bog1, final Map bog2) { 16 | super(bog1, bog2); 17 | similarity = new BM25Similarity(); 18 | } 19 | 20 | @Override 21 | public double getSimVal() { 22 | return 0; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/GrossSongContourSilimarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.GeneralMaximalVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.voicesimilarity.GrossContourSimilarity; 5 | 6 | /** 7 | * Created by asanyal on 10/2/15. 8 | * 9 | * Maximal gross contour over the songs similarity measure 10 | */ 11 | public class GrossSongContourSilimarity extends GeneralMaximalVoiceSimilarity { 12 | 13 | /** 14 | * Basic constructor for gross contour similarity 15 | */ 16 | public GrossSongContourSilimarity() { 17 | super(new GrossContourSimilarity()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/testdata/musicxml/attributesTestData.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 3 | 4 | -3 5 | minor 6 | 7 | 11 | 12 | 13 | G 14 | 4 15 | 16 | 2 17 | eighth 18 | up 19 | 20 | 21 |

22 | 23 | 24 | 25 | single 26 | Wärst 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/CountDistanceSongSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.GeneralMaximalVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.voicesimilarity.CountDistanceSimilarity; 5 | 6 | /** 7 | * Created by asanyal on 11/7/15. 8 | * 9 | * The count distance similarity measure extended for songs 10 | */ 11 | public class CountDistanceSongSimilarity extends GeneralMaximalVoiceSimilarity { 12 | 13 | /** 14 | * Basic constructor for generic maximal similarity 15 | */ 16 | public CountDistanceSongSimilarity() { 17 | super(new CountDistanceSimilarity()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modulo7log4.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=DEBUG, stdout, file 3 | 4 | # Redirect log messages to console 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 9 | 10 | # Redirect log messages to a log file, support file rolling. 11 | log4j.appender.file=org.apache.log4j.RollingFileAppender 12 | log4j.appender.file.File=log4j-modulo7.log 13 | log4j.appender.file.MaxFileSize=5MB 14 | log4j.appender.file.MaxBackupIndex=10 15 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 17 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/exceptions/Modulo7InvalidOctaveRangeException.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.exceptions; 2 | 3 | /** 4 | * Created by asanyal on 7/14/2015. 5 | * 6 | * Exception thrown when invalid octave ranges are given which 7 | * modulo7 does not understand (octave ranges are numbers between 8 | * 0 to 8 for standard musical instruments) 9 | * 10 | */ 11 | public class Modulo7InvalidOctaveRangeException extends Modulo7BaseException { 12 | public Modulo7InvalidOctaveRangeException(String message) { 13 | super(message); 14 | } 15 | 16 | public Modulo7InvalidOctaveRangeException(Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | public Modulo7InvalidOctaveRangeException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/JacardSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by asanyal on 12/19/15. 7 | * 8 | * Jacard similarity for bag of words representation 9 | */ 10 | public class JacardSimilarity extends BOWSimilarity { 11 | /** 12 | * Base constructor 13 | * 14 | * @param bog1 15 | * @param bog2 16 | */ 17 | public JacardSimilarity(Map bog1, Map bog2) { 18 | super(bog1, bog2); 19 | } 20 | 21 | @Override 22 | public double getSimVal() { 23 | double dotProd = v1.dotProduct(v2); 24 | return dotProd / (getVectorSum(v1) + getVectorSum(v2) - dotProd); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/enginetests/CacheTest.java: -------------------------------------------------------------------------------- 1 | package enginetests; 2 | 3 | import com.modulo7.engine.cache.Modulo7Cache; 4 | import org.junit.Test; 5 | 6 | import java.util.LinkedHashSet; 7 | 8 | /** 9 | * Created by asanyal on 11/6/15. 10 | * 11 | * Test for the modulo7 caching mechanism 12 | */ 13 | public class CacheTest { 14 | 15 | /** 16 | * Test case for cache 17 | */ 18 | @Test 19 | public void cacheTett() { 20 | Modulo7Cache cache = new Modulo7Cache(); 21 | 22 | // Song similarity to class , useful for dynamically calling classes during similarity metric analysis 23 | LinkedHashSet values = new LinkedHashSet() {{ 24 | add("blah"); 25 | add("black"); 26 | }}; 27 | 28 | cache.cacheQueryResults("blah", values); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/MaxMelodicEditDistanceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.GeneralMaximalVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.voicesimilarity.RawMelodicEditDistanceSimilarity; 5 | 6 | /** 7 | * Created by asanyal on 9/24/15. 8 | * 9 | * Generalized version of the raw melodic edit distance 10 | */ 11 | public class MaxMelodicEditDistanceSimilarity extends GeneralMaximalVoiceSimilarity { 12 | 13 | /** 14 | * Edit distance over an entire song pairwise and then returns the maximum 15 | */ 16 | public MaxMelodicEditDistanceSimilarity() { 17 | super(new RawMelodicEditDistanceSimilarity()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/parsertests/AudiverisMusicSheetXMLTest.java: -------------------------------------------------------------------------------- 1 | package parsertests; 2 | 3 | import com.modulo7.common.interfaces.AbstractAnalyzer; 4 | import com.modulo7.image.AudiverisSheetAnalyzer; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Created by asanyal on 9/9/15. 9 | * 10 | * Audiveris test cases for Optical Music recognition 11 | * 12 | * TODO : Fix this 13 | */ 14 | public class AudiverisMusicSheetXMLTest { 15 | 16 | /** 17 | * Sanity test case for audiveris test case 18 | */ 19 | @Test 20 | public void audiverisSanityTest() { 21 | final String sheetLocation = "./src/test/testdata/sheet/allegretto.png"; 22 | AbstractAnalyzer analyzer = new AudiverisSheetAnalyzer(sheetLocation); 23 | // final Song song = analyzer.getSongRepresentation(); 24 | // Assert.assertNotNull(song); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/lyricssimilarity/LyricsTFIDFSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.lyricssimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractLyricsSimilarity; 4 | import com.modulo7.nlp.lyrics.Lyrics; 5 | import org.apache.lucene.search.similarities.DefaultSimilarity; 6 | import org.apache.lucene.search.similarities.TFIDFSimilarity; 7 | 8 | /** 9 | * Created by asanyal on 10/2/15. 10 | * 11 | * Classical lyrics simialarity on the TFIDF measure 12 | * 13 | * TODO : Complete this 14 | */ 15 | public class LyricsTFIDFSimilarity implements AbstractLyricsSimilarity { 16 | 17 | @Override 18 | public double getSimilarity(final Lyrics thisLyrics, final Lyrics thatLyrics) { 19 | 20 | 21 | TFIDFSimilarity similarity = new DefaultSimilarity(); 22 | 23 | 24 | return 0.0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/interfaces/AbstractVoiceVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.interfaces; 2 | 3 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 4 | 5 | /** 6 | * Created by asanyal on 9/8/15. 7 | * 8 | * Vector space models but for individual voices instead of songs 9 | */ 10 | public interface AbstractVoiceVector { 11 | 12 | /** 13 | * Getter for the vector length associated with this vector 14 | * @return 15 | */ 16 | public int getVectorLength(); 17 | 18 | /** 19 | * Computes the vector representation from the elements in 20 | * the song representation of Modulo7 21 | */ 22 | public void computeVectorRepresentation(final Voice voice); 23 | 24 | /** 25 | * Gets the internal representation of the vector 26 | * @return 27 | */ 28 | public T getInternalRepresentation(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/contoursimilarity/SteinbeckContourSimililarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.contoursimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.SongContourSimilarity; 5 | import com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour.SteinbeckContour; 6 | 7 | /** 8 | * Created by asanyal on 10/4/15. 9 | * 10 | * Steinbeck contour similarity measure for arbitrary voice similarities 11 | */ 12 | public class SteinbeckContourSimililarity extends SongContourSimilarity { 13 | /** 14 | * Basic constructor 15 | * 16 | * @param internalVoiceSimilarity 17 | */ 18 | public SteinbeckContourSimililarity(final AbstractVoiceSimilarity internalVoiceSimilarity) { 19 | super(internalVoiceSimilarity, new SteinbeckContour()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/contoursimilarity/NaturalContourSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.contoursimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.SongContourSimilarity; 5 | import com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour.NaturalContour; 6 | 7 | /** 8 | * Created by asanyal on 10/4/15. 9 | * 10 | * Simple natural contour similarity, extending any voice similarity to natural contour 11 | */ 12 | public class NaturalContourSimilarity extends SongContourSimilarity { 13 | 14 | /** 15 | * Basic constructor 16 | * 17 | * @param internalVoiceSimilarity 18 | */ 19 | public NaturalContourSimilarity(final AbstractVoiceSimilarity internalVoiceSimilarity) { 20 | super(internalVoiceSimilarity, new NaturalContour()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/contoursimilarity/MullensefsteinContourSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.contoursimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.SongContourSimilarity; 5 | import com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour.MullensiefenContour; 6 | 7 | /** 8 | * Created by asanyal on 10/4/15. 9 | * 10 | * Mullefenstein contour similarity for arbitrary voice similarity 11 | */ 12 | public class MullensefsteinContourSimilarity extends SongContourSimilarity { 13 | /** 14 | * Basic constructor 15 | * 16 | * @param internalVoiceSimilarity 17 | */ 18 | public MullensefsteinContourSimilarity(final AbstractVoiceSimilarity internalVoiceSimilarity) { 19 | super(internalVoiceSimilarity, new MullensiefenContour()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/testdata/musicxml/chord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | C 6 | 4 7 | 8 | 1 9 | 10 | 11 | 12 | 13 | E 14 | -1 15 | 4 16 | 17 | 1 18 | 19 | 20 | 21 | 22 | G 23 | 4 24 | 25 | 1 26 | 27 | 28 | 29 | B 30 | 4 31 | 32 | 1 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/java/BasicTests.java: -------------------------------------------------------------------------------- 1 | import com.modulo7.engine.processing.Modulo7QueryProcessingEngine; 2 | import org.junit.Assert; 3 | import org.junit.Test; 4 | 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * Created by asanyal on 10/8/15. 10 | * 11 | * Basic test cases to maintain internal consistency 12 | */ 13 | public class BasicTests { 14 | 15 | /** 16 | * Test to check if the regexps in Modulo7 actually work 17 | */ 18 | @Test 19 | public void patternTest() { 20 | Pattern criteriaPattern = Modulo7QueryProcessingEngine.CRITERIA_PATTERNS; 21 | final String polyphonicExpr = "polyphonic is true"; 22 | Matcher matcher = criteriaPattern.matcher(polyphonicExpr); 23 | Assert.assertTrue(matcher.find()); 24 | 25 | final String badExpr = "blah is blah"; 26 | Matcher matcher1 = criteriaPattern.matcher(badExpr); 27 | Assert.assertFalse(matcher1.find()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/ScaleTypeCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.modulo7.common.interfaces.AbstractCriteria; 4 | import com.modulo7.musicstatmodels.representation.metadata.ScaleType; 5 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 6 | 7 | /** 8 | * Created by asanyal on 12/26/15. 9 | * 10 | * Cross check for the scale being of a particular type 11 | */ 12 | public class ScaleTypeCriteria implements AbstractCriteria { 13 | 14 | // The scale type for this criteria 15 | private ScaleType scaleType; 16 | 17 | /** 18 | * Constructor for key signature 19 | * @param requiredScale 20 | */ 21 | public ScaleTypeCriteria(final ScaleType requiredScale) { 22 | this.scaleType = requiredScale; 23 | } 24 | 25 | @Override 26 | public boolean getCriteriaEvaluation(final Song song) { 27 | return song.getMetadata().getKeySignature().getScale().equals(scaleType); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/musicmatch/LyricsBagOfWordsFormat.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.musicmatch; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Created by asanyal on 11/2/15. 7 | * 8 | * This is the bag of words format as used by music match dataset 9 | */ 10 | public class LyricsBagOfWordsFormat { 11 | 12 | // The ground truth dataset 13 | private BagOfWordsDataSet groundTruthDataSet; 14 | 15 | /** 16 | * Basic constructor for lyrics 17 | * 18 | * @param groundTruthFile 19 | * @throws IOException 20 | */ 21 | public LyricsBagOfWordsFormat(final String groundTruthFile) throws IOException { 22 | groundTruthDataSet = new BagOfWordsDataSet(groundTruthFile); 23 | } 24 | 25 | /** 26 | * Gets the bag of words for a MSD track ID 27 | * @param trackID 28 | * @return 29 | */ 30 | public BagOfWordsDataElement getBagOfWords(final String trackID) { 31 | return groundTruthDataSet.getBagOfWords(trackID); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/include/HoughTransform.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HOUGHTRANSFORM_H 2 | #define HOUGHTRANSFORM_H 3 | 4 | #include "opencv2/highgui/highgui.hpp" 5 | #include "opencv2/imgproc/imgproc.hpp" 6 | 7 | #if defined(_WIN32) && defined(DLL_EXPORT) 8 | #define LIB_FUNC __declspec(dllimport) 9 | #else 10 | #define LIB_FUNC 11 | #endif 12 | 13 | class LIB_FUNC HoughLinesTransform 14 | { 15 | private: 16 | 17 | // Matrix representations of source, destination and intermediate destination representations of 18 | // Images in the process of transforms being applied to it 19 | cv::Mat src, dst, cdst; 20 | 21 | // place holder for file name 22 | char* filename; 23 | 24 | // Apply the hogue transform on the given file 25 | void getLinesFromHogueTransform(); 26 | 27 | // Removing 28 | void removeLinesFromImage(); 29 | 30 | public: 31 | 32 | // Default constructor for the hogue transform 33 | // Accepts file name and contstructs the matrix representation 34 | HoughLinesTransform(const char * filename); 35 | }; 36 | 37 | #endif HOUGHTRANSFORM_H -------------------------------------------------------------------------------- /src/main/java/com/modulo7/fun/HelloWorldGUI.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.fun; 2 | 3 | /** 4 | * Created by asanyal on 9/27/15. 5 | * 6 | * A hello world app in java fx 7 | */ 8 | import javafx.application.Application; 9 | import javafx.scene.Scene; 10 | import javafx.scene.control.Button; 11 | import javafx.scene.layout.StackPane; 12 | import javafx.stage.Stage; 13 | 14 | public class HelloWorldGUI extends Application { 15 | 16 | @Override 17 | public void start(Stage primaryStage) { 18 | Button btn = new Button(); 19 | btn.setText("Hello and welcome to Modulo7"); 20 | btn.setOnAction(event -> processGUIMode()); 21 | 22 | StackPane root = new StackPane(); 23 | root.getChildren().add(btn); 24 | 25 | Scene scene = new Scene(root, 300, 250); 26 | 27 | primaryStage.setTitle("Hello World!"); 28 | primaryStage.setScene(scene); 29 | primaryStage.show(); 30 | } 31 | 32 | private void processGUIMode() { 33 | 34 | } 35 | 36 | public static void main(String[] args) { 37 | launch(args); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/STABVoiceClassificationCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.modulo7.common.interfaces.AbstractCriteria; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceClass; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * Created by asanyal on 10/18/15. 13 | * 14 | * Most choral music have the nice stab voice classification, but most pop and rock 15 | * songs dont follow into that purview. Hence 16 | */ 17 | public class STABVoiceClassificationCriteria implements AbstractCriteria { 18 | 19 | @Override 20 | public boolean getCriteriaEvaluation(final Song song) { 21 | Set voiceTypesPresent = song.getVoices().stream().map(Voice::estimateVoiceClass).collect(Collectors.toSet()); 22 | return !voiceTypesPresent.contains(VoiceClass.GENERIC) && voiceTypesPresent.size() == 4; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/KeySignatureEqualityCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.modulo7.common.interfaces.AbstractCriteria; 4 | import com.modulo7.musicstatmodels.representation.metadata.KeySignature; 5 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 6 | 7 | /** 8 | * Created by asanyal on 9/16/15. 9 | * 10 | * A simple criteria based on whether the key signature is the same 11 | * as an input key signature 12 | */ 13 | public class KeySignatureEqualityCriteria implements AbstractCriteria { 14 | 15 | // Desired Key signature element 16 | private KeySignature keySignature; 17 | 18 | /** 19 | * Constructor for key signature 20 | * @param requiredKeySignature 21 | */ 22 | public KeySignatureEqualityCriteria(final KeySignature requiredKeySignature) { 23 | this.keySignature = requiredKeySignature; 24 | } 25 | 26 | @Override 27 | public boolean getCriteriaEvaluation(final Song song) { 28 | return song.getMetadata().getKeySignature().equals(keySignature); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/AveragePitchDuration.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractStatistic; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | 8 | /** 9 | * Created by asanyal on 1/6/16. 10 | * 11 | * Statistic for calculating the average pitch duration 12 | */ 13 | public class AveragePitchDuration implements AbstractStatistic { 14 | @Override 15 | public Double getStatistic(final Song song) { 16 | 17 | double averagePitchDuration = 0.0; 18 | int numDurations = 0; 19 | 20 | for (final Voice voice : song.getVoices()) { 21 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 22 | averagePitchDuration += instant.getDuration(); 23 | numDurations++; 24 | } 25 | } 26 | 27 | return averagePitchDuration / numDurations; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/lastfm/SongSimilarityElement.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.lastfm; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by asanyal on 11/9/15. 7 | * 8 | * An element of song similarity 9 | */ 10 | public class SongSimilarityElement implements Serializable { 11 | 12 | // Similarity value 13 | private double similarityValue; 14 | 15 | // Song ID 16 | private String songID; 17 | 18 | /** 19 | * Default constructor for element 20 | * @param songID 21 | * @param similarityValue 22 | */ 23 | public SongSimilarityElement(final String songID, final double similarityValue) { 24 | this.songID = songID; 25 | this.similarityValue = similarityValue; 26 | } 27 | 28 | /** 29 | * Gets the similarity value 30 | * @return 31 | */ 32 | public double getSimilarityValue() { 33 | return similarityValue; 34 | } 35 | 36 | /** 37 | * Gets the song id for a given song 38 | * @return 39 | */ 40 | public String getSongID() { 41 | return songID; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/ROCDataPoint.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation; 2 | 3 | /** 4 | * Created by asanyal on 12/24/15. 5 | * 6 | * A particular data point that would be present in the 7 | * ROC curve for threshhold based measures 8 | */ 9 | public class ROCDataPoint { 10 | 11 | // True positive rate 12 | private double tpr; 13 | 14 | // False positive rate 15 | private double fpr; 16 | 17 | /** 18 | * Default constructor for the ROC data point 19 | * @param truePositiveRate 20 | * @param falsePositiveRate 21 | */ 22 | public ROCDataPoint(final double truePositiveRate, final double falsePositiveRate) { 23 | this.tpr = truePositiveRate; 24 | this.fpr = falsePositiveRate; 25 | } 26 | 27 | /** 28 | * Getter for True positive rate 29 | * @return 30 | */ 31 | public double getTruePositiveRate() { 32 | return tpr; 33 | } 34 | 35 | /** 36 | * Getter fro True negative rate 37 | * @return 38 | */ 39 | public double getFalsePositiveRate() { 40 | return fpr; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/buildingblocks/ChordProgression.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.buildingblocks; 2 | 3 | import com.modulo7.musicstatmodels.representation.metadata.KeySignature; 4 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * Created by asanyal on 10/2/15. 10 | * 11 | * A chord progression is a basic data structure that 12 | * takes into account some prevalent chord sequences that 13 | * are present in music in general 14 | */ 15 | public class ChordProgression { 16 | 17 | private static final String NOT_A_PROGRESSION = "NOTPROGRESSION"; 18 | 19 | private static String getChordProgressionString(final Set candidateChordProgession, final KeySignature signature) { 20 | 21 | final String key = signature.getKey(); 22 | 23 | for (final VoiceInstant voiceInstant : candidateChordProgession) { 24 | if (!voiceInstant.isChord()) { 25 | return NOT_A_PROGRESSION; 26 | } else { 27 | 28 | } 29 | } 30 | 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/GenreLabels.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation; 2 | 3 | import java.io.Serializable; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by asanyal on 12/22/15. 8 | * 9 | * For a given track id, get the annotated list of genres 10 | */ 11 | public class GenreLabels implements Serializable { 12 | 13 | // Track id for particular track 14 | private String trackId; 15 | 16 | // List of genres that particular track belongs to 17 | private Set genreList; 18 | 19 | /** 20 | * Default constructor 21 | * 22 | * @param trackId 23 | * @param genreList 24 | */ 25 | public GenreLabels(final String trackId, final Set genreList) { 26 | this.trackId = trackId; 27 | this.genreList = genreList; 28 | } 29 | 30 | /** 31 | * Get track ID 32 | * @return 33 | */ 34 | public String getTrackId() { 35 | return trackId; 36 | } 37 | 38 | /** 39 | * Get genre list for this particular 40 | * @return 41 | */ 42 | public Set getGenreList() { 43 | return genreList; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/parsertests/MP3Test.java: -------------------------------------------------------------------------------- 1 | package parsertests; 2 | 3 | import com.echonest.api.v4.EchoNestException; 4 | import com.modulo7.common.interfaces.AbstractAnalyzer; 5 | import com.modulo7.acoustics.EchoNestBasicMP3Analyzer; 6 | import com.modulo7.common.exceptions.Modulo7NoSuchFileOrDirectoryException; 7 | import com.modulo7.common.utils.MusicSources; 8 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | /** 13 | * Created by asanyal on 8/29/15. 14 | * 15 | * Junit test cases for mp3 files 16 | */ 17 | public class MP3Test { 18 | 19 | @Test 20 | public void mp3SanityTest() { 21 | final String mp3Location = "./src/test/testdata/mp3/stairway_to_heaven.mp3"; 22 | 23 | try { 24 | AbstractAnalyzer analyzer = new EchoNestBasicMP3Analyzer(mp3Location); 25 | Song song = analyzer.getSongRepresentation(); 26 | Assert.assertNotNull(song); 27 | Assert.assertEquals(song.getSource(), MusicSources.MP3); 28 | } catch (EchoNestException | Modulo7NoSuchFileOrDirectoryException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/LyricalSemanticIntent.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractStatistic; 4 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 5 | import com.modulo7.nlp.lyrics.Lyrics; 6 | import com.modulo7.nlp.nlpengine.AlchemyEngine; 7 | import org.apache.log4j.Logger; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * Created by asanyal on 10/10/15. 13 | * 14 | * Gets a semantic score for the lyrical content for a song 15 | */ 16 | public class LyricalSemanticIntent implements AbstractStatistic { 17 | 18 | // Logger for lyrical semantic intent 19 | private static Logger logger = Logger.getLogger(LyricalSemanticIntent.class); 20 | 21 | @Override 22 | public Double getStatistic(final Song song) { 23 | 24 | Lyrics lyrics = song.getLyrics(); 25 | 26 | try { 27 | AlchemyEngine engine = new AlchemyEngine(); 28 | return engine.sentimentAnalysis(lyrics.getLyricsOfSong()).getScore(); 29 | } catch (IOException e) { 30 | logger.error(e.getMessage()); 31 | } 32 | 33 | return 0.0; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/songvectors/ContourGradientVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors; 2 | 3 | import com.modulo7.common.interfaces.AbstractContour; 4 | import com.modulo7.common.interfaces.AbstractSongVector; 5 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by asanyal on 9/8/15. 11 | * 12 | * Expression giving the gradient 13 | */ 14 | public class ContourGradientVector implements AbstractSongVector { 15 | 16 | // A contour algorithm input to the gradient vector 17 | private AbstractContour contour; 18 | 19 | /** 20 | * Basic constructor of the gradient vector representation of the voice 21 | * @param contour 22 | */ 23 | public ContourGradientVector(final AbstractContour contour) { 24 | this.contour = contour; 25 | } 26 | 27 | @Override 28 | public void computeVectorRepresentation(final Song song) { 29 | 30 | } 31 | 32 | @Override 33 | public List getInternalRepresentation() { 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/monophonic/VoiceTag.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.monophonic; 2 | 3 | import com.modulo7.common.utils.Modulo7Globals; 4 | import com.modulo7.musicstatmodels.representation.metadata.Clef; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * Created by asanyal on 9/8/15. 10 | * 11 | * Metadata associated with voices ; 12 | * 13 | * TODO : Expand on this with meaningful abstractions 14 | */ 15 | public class VoiceTag implements Serializable { 16 | 17 | // The type of instrument being played 18 | private String instrumentName = Modulo7Globals.UNKNOWNSTRING; 19 | 20 | // In which clef is this voice 21 | private Clef clef = Clef.Unknown; 22 | 23 | public VoiceTag() { 24 | 25 | } 26 | 27 | /** 28 | * Standard voice tag constructor 29 | * @param instrumentName 30 | * @param clef 31 | */ 32 | public VoiceTag(final String instrumentName, final Clef clef) { 33 | this.instrumentName = instrumentName; 34 | this.clef = clef; 35 | } 36 | 37 | public String getInstrumentName() { 38 | return instrumentName; 39 | } 40 | 41 | public Clef getClef() { 42 | return clef; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/playback/MP3PlayBack.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.playback; 2 | 3 | import javazoom.jl.decoder.JavaLayerException; 4 | import javazoom.jl.player.Player; 5 | import org.apache.log4j.Logger; 6 | 7 | import java.io.BufferedInputStream; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | 11 | /** 12 | * Created by asanyal on 10/22/15. 13 | * 14 | * Class that plays back an mp3 file given as input 15 | */ 16 | public class MP3PlayBack implements AbstractPlayBack { 17 | 18 | private String mp3File; 19 | 20 | // Logger for mp3 playback 21 | private static final Logger logger =Logger.getLogger(MP3PlayBack.class); 22 | 23 | // Default playback constructor 24 | public MP3PlayBack(final String fileName) { 25 | mp3File = fileName; 26 | } 27 | 28 | @Override 29 | public void play() { 30 | FileInputStream fis; 31 | try { 32 | fis = new FileInputStream(mp3File); 33 | BufferedInputStream bis = new BufferedInputStream(fis); 34 | Player player = new Player(bis); 35 | player.play(); 36 | } catch (FileNotFoundException | JavaLayerException e) { 37 | logger.error(e.getMessage()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/nlp/models/SentimentModel.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.nlp.models; 2 | 3 | import com.likethecolor.alchemy.api.entity.SentimentAlchemyEntity; 4 | 5 | /** 6 | * Created by asanyal on 10/10/15. 7 | * 8 | * Modulo7 representation of the sentiment analysis of lyrics 9 | */ 10 | public class SentimentModel { 11 | 12 | // The score the sentiment, positive scores are for happy lyrics and negative scores are for sad or angry lyrics 13 | private double score; 14 | 15 | // The intent of the sentiment 16 | private SentimentAlchemyEntity.TYPE intent; 17 | 18 | /** 19 | * Create a sentiment model for Modulo7 20 | * @param score 21 | * @param intent 22 | */ 23 | public SentimentModel(final double score, final SentimentAlchemyEntity.TYPE intent) { 24 | this.intent = intent; 25 | 26 | this.score = score; 27 | assert (score >= -1.0 && score <= 1.0); 28 | } 29 | 30 | /** 31 | * Gets the score 32 | * @return 33 | */ 34 | public double getScore() { 35 | return score; 36 | } 37 | 38 | /** 39 | * Gets the sentiment type 40 | * @return 41 | */ 42 | public SentimentAlchemyEntity.TYPE getIntent() { 43 | return intent; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/nlptests/NLPUtilsTest.java: -------------------------------------------------------------------------------- 1 | package nlptests; 2 | 3 | import com.modulo7.nlp.NLPUtils; 4 | import junit.framework.Assert; 5 | import org.junit.Test; 6 | import org.apache.lucene.queryparser.classic.ParseException; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by asanyal on 8/18/15. 12 | * 13 | * Junit tests 14 | */ 15 | public class NLPUtilsTest { 16 | 17 | /** 18 | * Basic test case for modulo7 porter for NLP 19 | */ 20 | @Test 21 | public void stemmerTest() throws ParseException, IOException { 22 | 23 | String inputSetence = "Hello my name is Arunav Sanyal, I liked horse back riding since I was a child"; 24 | String actualStemmedText = "Hello my name Arunav Sanyal I like hors back ride sinc I child"; 25 | 26 | String stemmedSentence = NLPUtils.stemmer(inputSetence); 27 | 28 | Assert.assertEquals(actualStemmedText, stemmedSentence); 29 | 30 | String nextInputSentence = "Baba black sheep have you any wool, yes sir, yes sir three bags full"; 31 | String actualNextStemmedText = "Baba black sheep have you ani wool ye sir ye sir three bag full"; 32 | 33 | String nextStemmedSentence = NLPUtils.stemmer(nextInputSentence); 34 | 35 | Assert.assertEquals(actualNextStemmedText, nextStemmedSentence); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/TimeSignatureEqualityCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.modulo7.common.interfaces.AbstractCriteria; 4 | import com.modulo7.musicstatmodels.representation.metadata.SongMetadata; 5 | import com.modulo7.musicstatmodels.representation.metadata.TimeSignature; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | 8 | /** 9 | * Created by asanyal on 10/10/15 10 | * 11 | * To check if a song has the same time signature as a desired value 12 | */ 13 | public class TimeSignatureEqualityCriteria implements AbstractCriteria { 14 | 15 | // The desired time signature of a song 16 | private TimeSignature timeSignature; 17 | 18 | /** 19 | * Basic constructor that takes as an argument the desired time signature 20 | * @param signature 21 | */ 22 | public TimeSignatureEqualityCriteria(final TimeSignature signature) { 23 | this.timeSignature = signature; 24 | } 25 | 26 | @Override 27 | public boolean getCriteriaEvaluation(final Song song) { 28 | SongMetadata metadata = song.getMetadata(); 29 | 30 | if (metadata != null) { 31 | TimeSignature currSig = metadata.getTimeSignature(); 32 | return currSig == timeSignature; 33 | } 34 | 35 | return false; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/parsertests/MidiTest.java: -------------------------------------------------------------------------------- 1 | package parsertests; 2 | 3 | import com.modulo7.common.exceptions.Modulo7NoSuchFileOrDirectoryException; 4 | import com.modulo7.common.interfaces.AbstractAnalyzer; 5 | import com.modulo7.acoustics.MidiToSongConverter; 6 | import com.modulo7.common.utils.MusicSources; 7 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | import javax.sound.midi.InvalidMidiDataException; 12 | 13 | /** 14 | * Created by asanyal on 8/20/15. 15 | * 16 | * Test cases related to parsing the midi format 17 | */ 18 | public class MidiTest { 19 | 20 | /** 21 | * A basic test to sanity test whether a midi parser works or not 22 | * 23 | * @throws com.modulo7.common.exceptions.Modulo7NoSuchFileOrDirectoryException 24 | * @throws InvalidMidiDataException 25 | */ 26 | @Test 27 | public void midiSanityTest() throws InvalidMidiDataException, Modulo7NoSuchFileOrDirectoryException { 28 | final String midiLocation = "./src/test/testdata/midi/test.mid"; 29 | AbstractAnalyzer midiAnalyzer = new MidiToSongConverter(midiLocation); 30 | 31 | Song song = midiAnalyzer.getSongRepresentation(); 32 | 33 | Assert.assertNotNull(song); 34 | Assert.assertEquals(song.getSource(), MusicSources.MIDI); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/VoiceTonalHistogramSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongSimilarity; 4 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 5 | import com.modulo7.common.utils.MusicSources; 6 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 7 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 8 | import com.modulo7.musicstatmodels.similarity.songsimilarity.TonalHistogramSimilarity; 9 | 10 | /** 11 | * Created by asanyal on 9/18/15. 12 | * 13 | * Tonal histogram similarity between two voices 14 | */ 15 | public class VoiceTonalHistogramSimilarity implements AbstractVoiceSimilarity { 16 | 17 | /** 18 | * Gets the tonal histogram similarity between two voices 19 | * @param first 20 | * @param second 21 | * @return 22 | */ 23 | @Override 24 | public double getSimilarity(final Voice first, final Voice second) { 25 | 26 | final Song firstSong = new Song(first, MusicSources.UNKNOWN); 27 | final Song secondSong = new Song(second, MusicSources.UNKNOWN); 28 | 29 | AbstractSongSimilarity similarity = new TonalHistogramSimilarity(); 30 | 31 | return similarity.getSimilarity(firstSong, secondSong); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/criteria/PositiveLyricsIntentCriteria.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.criteria; 2 | 3 | import com.likethecolor.alchemy.api.entity.SentimentAlchemyEntity; 4 | import com.modulo7.common.interfaces.AbstractCriteria; 5 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 6 | import com.modulo7.nlp.models.SentimentModel; 7 | import com.modulo7.nlp.nlpengine.AlchemyEngine; 8 | import org.apache.log4j.Logger; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Created by asanyal on 10/10/15. 14 | * 15 | * Is the lyrical content positive in its semantic intent ? If so the criteria is satisfied 16 | */ 17 | public class PositiveLyricsIntentCriteria implements AbstractCriteria { 18 | 19 | // Logger for the positive lyrics intent 20 | private static Logger logger = Logger.getLogger(PositiveLyricsIntentCriteria.class); 21 | 22 | @Override 23 | public boolean getCriteriaEvaluation(final Song song) { 24 | try { 25 | AlchemyEngine engine = new AlchemyEngine(); 26 | SentimentModel model = engine.sentimentAnalysis(song.getLyrics().getLyricsOfSong()); 27 | return model.getIntent() == SentimentAlchemyEntity.TYPE.POSITIVE; 28 | } catch (IOException e) { 29 | logger.error(e.getMessage()); 30 | } 31 | 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/misc/TonalityAlignment.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.misc; 2 | 3 | /** 4 | * Created by asanyal on 1/2/16. 5 | * 6 | * A class which dictates the members of the tonality alignment concept 7 | * (An example of which would be the smith waterman algorithm) 8 | */ 9 | public class TonalityAlignment { 10 | 11 | // One string 12 | private String firstStr; 13 | 14 | // Other string 15 | private String secondStr; 16 | 17 | // Maximal alignment noticed 18 | private int maxContiguousTonalCommonality; 19 | 20 | /** 21 | * Default constructor 22 | * @param firstStr 23 | * @param secondStr 24 | * @param maxContiguousTonalCommonality 25 | */ 26 | public TonalityAlignment(String firstStr, String secondStr, final int maxContiguousTonalCommonality) { 27 | this.firstStr = firstStr; 28 | this.secondStr = secondStr; 29 | this.maxContiguousTonalCommonality = maxContiguousTonalCommonality; 30 | } 31 | 32 | /** 33 | * Displays the alignment as determined by an alignment algorithm 34 | */ 35 | public void displayAlignment() { 36 | System.out.println("The alignment is displayed below"); 37 | System.out.println(firstStr); 38 | System.out.println(secondStr); 39 | System.out.println("The maximal contiguous alignment score" + maxContiguousTonalCommonality); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/lastfm/SongBagLyricsGenreMap.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.lastfm; 2 | 3 | import com.modulo7.pureresearch.metadataestimation.GenreLabels; 4 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * Created by asanyal on 12/22/15. 10 | * 11 | * An association between the lyrics of a song and its bag of words 12 | * lyrics format 13 | */ 14 | public class SongBagLyricsGenreMap implements Serializable { 15 | 16 | // The last fm track ID 17 | private String trackID; 18 | 19 | // The genre labels associated with the track id 20 | private GenreLabels labels; 21 | 22 | // The bag of words representation of a song 23 | private BagOfWordsDataElement bagOfWords; 24 | 25 | /** 26 | * 27 | * @param trackID 28 | * @param labels 29 | * @param bagOfWords 30 | */ 31 | public SongBagLyricsGenreMap(final String trackID, final GenreLabels labels, final BagOfWordsDataElement bagOfWords) { 32 | this.trackID = trackID; 33 | this.labels = labels; 34 | this.bagOfWords = bagOfWords; 35 | } 36 | 37 | public String getTrackID() { 38 | return trackID; 39 | } 40 | 41 | public GenreLabels getLabels() { 42 | return labels; 43 | } 44 | 45 | public BagOfWordsDataElement getBagOfWords() { 46 | return bagOfWords; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/metadata/ScaleType.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.metadata; 2 | 3 | /** 4 | * Created by asanyal on 6/29/2015. 5 | * 6 | * Different types of scales that in existence in western music. 7 | * 8 | * Major Scale : Standard major scale, also called the happy sounding scale 9 | * Minor Scale : Standard minor scale, also called the sad sounding scale 10 | */ 11 | public enum ScaleType { 12 | 13 | MAJOR("MAJOR"), 14 | MINOR("MINOR"), 15 | UNKNOWN("UNKNOWN"); 16 | 17 | private final String scale; 18 | 19 | ScaleType(final String scale) { 20 | this.scale = scale.toUpperCase(); 21 | } 22 | 23 | /** 24 | * Gets the scale type given a string representation 25 | * @param inputStr 26 | * @return 27 | */ 28 | public static ScaleType getScaleTypeFromString(final String inputStr) { 29 | String actualStr = inputStr.toUpperCase(); 30 | 31 | if (actualStr.equals("MAJOR") || actualStr.equals("MAJ")) { 32 | return MAJOR; 33 | } else if (actualStr.equals("MINOR") || actualStr.equals("MIN")) { 34 | return MINOR; 35 | } else { 36 | return UNKNOWN; 37 | } 38 | } 39 | 40 | /** 41 | * Gets the string representation of the scale 42 | * @return 43 | */ 44 | public String getScale() { 45 | return scale; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /doc/similarity_description: -------------------------------------------------------------------------------- 1 | Similarity measures for Music theoretic criteria 2 | 3 | This document consists a description of all the similarity measures that are addressed by Modulo7 4 | 5 | In that respect a good vector representation needs to be developed for the same. 6 | 7 | Various vector space representation for this regard as the follows :- 8 | 9 | 1. TonalHistogramVector - A vector representation of a document that considers bins of intervals. 10 | 2. Perfect/Minor/Major triple vector - A condensed vector representation that takes into account 11 | 12 | Adopting traditionAal IR approaches to music representation can be difficult. For that a documentation scheme is needed. 13 | I present my own documentation scheme (depending on tokenization of standard literature) 14 | 15 | 1. All notes will have their standard meaning. A, A#, B, C, ,C# D, D#, E, F, F#, G, G#, penalty of transformation is defined based on horizontal 16 | interval distance 17 | 18 | 2. All chords will be note appended by a suffix denoting chord type. The types are maj, min, dim etc. So an example token would be Emaj. 19 | 20 | This information Points one and two are per voice. Each voice is a sequence of such voice preceded by a voice index. 21 | 22 | 3. Title, Artist, Album, Key signature, Time Signature, Tempo and other parameters can be considered as time signature can be considered 23 | as title and other header information for the document. As such they can be queried separately -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/RawMelodicEditDistanceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.common.utils.Modulo7Utils; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import org.apache.lucene.search.spell.LevensteinDistance; 8 | 9 | /** 10 | * Created by asanyal on 9/1/15. 11 | * 12 | * Raw edit distance between two strings with raw pitch values, returns the average 13 | * over all the melodic distances computed pariwise between the voices 14 | * 15 | * This assumes both voices are in the same key signature for the operation to work 16 | */ 17 | public class RawMelodicEditDistanceSimilarity implements AbstractVoiceSimilarity { 18 | 19 | @Override 20 | public double getSimilarity(final Voice first, final Voice second) { 21 | 22 | final String firstSetDoc = first.getDocumentRepresentation(); 23 | final String secondSetDoc = second.getDocumentRepresentation(); 24 | 25 | String[] firstSplit = firstSetDoc.split(" "); 26 | String[] secondSplit = secondSetDoc.split(" "); 27 | 28 | return (double) (1 - (Modulo7Utils.levensteinDistanceOnArbitraryTokens(firstSplit, secondSplit)) / Math.max(firstSplit.length, secondSplit.length)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/acoustics/EchoNestKeySignatureEstimator.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.acoustics; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadKeyException; 4 | import com.modulo7.common.utils.Modulo7Globals; 5 | import com.modulo7.musicstatmodels.representation.metadata.KeySignature; 6 | import com.modulo7.musicstatmodels.representation.metadata.ScaleType; 7 | 8 | /** 9 | * Created by asanyal on 9/9/15. 10 | * 11 | * Helper class for estimation for key signature 12 | */ 13 | public class EchoNestKeySignatureEstimator { 14 | 15 | /** 16 | * Helper method for acquiring key signature from a song 17 | * @param key 18 | * @param mode 19 | * @return 20 | * @throws Modulo7BadKeyException 21 | */ 22 | public static KeySignature estimateKeySignature(final int key, final int mode) throws Modulo7BadKeyException { 23 | 24 | if (key == -1 || mode == -1) { 25 | return null; 26 | } 27 | 28 | // Type of scale 29 | final ScaleType scaleType; 30 | 31 | if (mode == 1) { 32 | scaleType = ScaleType.MAJOR; 33 | } else if (mode == 0) { 34 | scaleType = ScaleType.MINOR; 35 | } else { 36 | scaleType = ScaleType.UNKNOWN; 37 | } 38 | 39 | final String keyStringRep = Modulo7Globals.NOTE_NAMES[(key + 3) % Modulo7Globals.NOTE_NAMES.length]; 40 | 41 | return new KeySignature(keyStringRep, scaleType); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/GrossContourSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | import com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour.GrossContour; 6 | import org.apache.lucene.search.spell.LevensteinDistance; 7 | 8 | /** 9 | * Created by asanyal on 9/24/15. 10 | * 11 | * A similarity measure based on the gross contour of melodies and their 12 | * edit distance 13 | */ 14 | public class GrossContourSimilarity implements AbstractVoiceSimilarity { 15 | 16 | /** 17 | * Returns similarity based on the gross contour representation of songs 18 | * @param first 19 | * @param second 20 | * @return 21 | */ 22 | @Override 23 | public double getSimilarity(final Voice first, final Voice second) { 24 | GrossContour contour = new GrossContour(); 25 | final String firstContourRep = contour.getContourRepresentaionOfVoice(first); 26 | final String secondContourRep = contour.getContourRepresentaionOfVoice(second); 27 | 28 | LevensteinDistance distance = new LevensteinDistance(); 29 | 30 | // Leveinstein distance is a misnomer in apache lucene, its actually a similarity measure 31 | return distance.getDistance(firstContourRep, secondContourRep); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/voicevectors/VoiceRawPitchVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.voicevectors; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.common.interfaces.AbstractVoiceVector; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.VoicePitchList; 7 | import org.apache.log4j.Logger; 8 | 9 | /** 10 | * Created by asanyal on 9/8/15. 11 | * 12 | * Raw pitch list for a voice 13 | */ 14 | public class VoiceRawPitchVector implements AbstractVoiceVector{ 15 | 16 | // Voice raw pitch vector logger 17 | private static final Logger logger = Logger.getLogger(VoiceRawPitchVector.class); 18 | 19 | // A pitch list representation for 20 | private VoicePitchList pitchList = new VoicePitchList(); 21 | 22 | @Override 23 | public int getVectorLength() { 24 | return pitchList.length(); 25 | } 26 | 27 | @Override 28 | public void computeVectorRepresentation(final Voice voice) { 29 | try { 30 | pitchList.computeVoicePitchSet(voice); 31 | } catch (Modulo7WrongNoteType e) { 32 | logger.error(e.getMessage()); 33 | } 34 | } 35 | 36 | @Override 37 | public VoicePitchList getInternalRepresentation() { 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/playback/MidiPlayBack.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.playback; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.jfugue.midi.MidiParser; 5 | import org.jfugue.pattern.Pattern; 6 | import org.jfugue.player.Player; 7 | import org.staccato.StaccatoParserListener; 8 | 9 | import javax.sound.midi.InvalidMidiDataException; 10 | import javax.sound.midi.MidiSystem; 11 | import javax.sound.midi.MidiUnavailableException; 12 | import java.io.File; 13 | import java.io.IOException; 14 | 15 | /** 16 | * Created by asanyal on 10/22/15. 17 | * 18 | * Midi playback module 19 | */ 20 | public class MidiPlayBack implements AbstractPlayBack { 21 | 22 | private File midiFile; 23 | 24 | private static final Logger logger = Logger.getLogger(MidiPlayBack.class); 25 | 26 | public MidiPlayBack(final String fileName) { 27 | midiFile = new File(fileName); 28 | } 29 | 30 | @Override 31 | public void play() { 32 | MidiParser parser = new MidiParser(); 33 | StaccatoParserListener listener = new StaccatoParserListener(); 34 | parser.addParserListener(listener); 35 | 36 | try { 37 | parser.parse(MidiSystem.getSequence(midiFile)); 38 | } catch (InvalidMidiDataException | IOException e) { 39 | logger.error(e.getMessage()); 40 | } 41 | 42 | Pattern staccatoPattern = listener.getPattern(); 43 | Player player = new Player(); 44 | player.play(staccatoPattern); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/monophonic/VoiceClass.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.monophonic; 2 | 3 | /** 4 | * Created by asanyal on 10/18/15. 5 | * 6 | * Classifications of voices in choral music 7 | */ 8 | public enum VoiceClass { 9 | SOPRAN0("soprano"), 10 | ALTO("alto"), 11 | TENOR("tenor"), 12 | BASS("bass"), 13 | GENERIC("generic"); // Generic voices are also voices which dont fit into any particular criteria 14 | 15 | final String voiceClass; 16 | 17 | VoiceClass(String voice) { 18 | voiceClass = voice; 19 | } 20 | 21 | /** 22 | * Gets the voice class string representation of the voice 23 | * @return 24 | */ 25 | public String getVoiceClassStringRep() { 26 | return voiceClass; 27 | } 28 | 29 | /** 30 | * Returns the voice class enum representation given string representation 31 | * @param strForm 32 | * @return 33 | */ 34 | public static VoiceClass getVoiceClassGivenString(final String strForm) { 35 | if (strForm.equalsIgnoreCase("soprano")) { 36 | return SOPRAN0; 37 | } else if (strForm.equalsIgnoreCase("alto")) { 38 | return ALTO; 39 | } else if (strForm.equalsIgnoreCase("tenor")) { 40 | return TENOR; 41 | } else if (strForm.equalsIgnoreCase("bass")) { 42 | return BASS; 43 | } else { 44 | return GENERIC; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/buildingblocks/Accidental.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.buildingblocks; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadAccidentalException; 4 | 5 | /** 6 | * Created by asanyal on 8/17/15. 7 | * 8 | * A class which represents the accidental on a note 9 | * 10 | * An accidental is a modification on the root note 11 | */ 12 | public enum Accidental { 13 | NONE, 14 | FLAT, 15 | SHARP, 16 | DOUBLEFLAT, 17 | DOUBLESHARP; 18 | 19 | // Empty constructor for the accidental 20 | Accidental() { 21 | 22 | } 23 | 24 | /** 25 | * Static method to acquire the delta from a base note given the type of accidental 26 | * 27 | * @param accidental 28 | * @return 29 | * @throws com.modulo7.common.exceptions.Modulo7BadAccidentalException 30 | */ 31 | public static int getPositionDelta(Accidental accidental) throws Modulo7BadAccidentalException { 32 | if (accidental.equals(Accidental.NONE)) 33 | return 0; 34 | else if (accidental.equals(Accidental.FLAT)) 35 | return -1; 36 | else if (accidental.equals(Accidental.SHARP)) 37 | return 1; 38 | else if (accidental.equals(Accidental.DOUBLEFLAT)) 39 | return -2; 40 | else if (accidental.equals(Accidental.DOUBLESHARP)) 41 | return 2; 42 | else 43 | throw new Modulo7BadAccidentalException("Bad accidental value passed"); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/processing/TonalAlignmentEngine.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.processing; 2 | 3 | import com.modulo7.engine.storage.DatabaseEngine; 4 | import com.modulo7.musicstatmodels.misc.TonalityAlignment; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import com.modulo7.musicstatmodels.similarity.genericsimilarity.SmithWatermanDistance; 8 | 9 | import java.util.Set; 10 | 11 | /** 12 | * Created by asanyal on 1/1/16. 13 | * 14 | * A specialist engine which procudes alignments based on tonality 15 | * and a given similarity measure 16 | * 17 | * Alignment looks for regions of songs that are similar to each other 18 | * and gives that as an output 19 | */ 20 | public class TonalAlignmentEngine { 21 | 22 | /** 23 | * Performs the tonality alignment operation 24 | * @param engine 25 | * @param refSong 26 | */ 27 | public void align(final DatabaseEngine engine, final Song refSong) { 28 | final Set allSongs = engine.getAllSongs(); 29 | 30 | for (final Song song : allSongs) { 31 | for (final Voice refVoice : refSong.getVoices()) { 32 | for (final Voice voice : song.getVoices()) { 33 | SmithWatermanDistance sim = new SmithWatermanDistance(); 34 | sim.getSmithWatermanDistance(refVoice, voice); 35 | TonalityAlignment alignment = sim.getAlignment(); 36 | alignment.displayAlignment(); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/antlr/Modulo7SQLBase.tokens: -------------------------------------------------------------------------------- 1 | SELECT=1 2 | MIDI=2 3 | SHEET=3 4 | MP3=4 5 | MUSICXML=5 6 | ON=6 7 | FROM=7 8 | WHERE=8 9 | AND=9 10 | OR=10 11 | IS=11 12 | NULL=12 13 | IN=13 14 | TRUE=14 15 | FALSE=15 16 | DIVIDE=16 17 | MOD=17 18 | PLUS=18 19 | MINUS=19 20 | NEGATION=20 21 | VERTBAR=21 22 | BITAND=22 23 | POWER_OP=23 24 | BINARY=24 25 | ESCAPE=25 26 | ASTERISK=26 27 | RPAREN=27 28 | LPAREN=28 29 | RBRACK=29 30 | LBRACK=30 31 | COLON=31 32 | ALL_FIELDS=32 33 | EQ=33 34 | LTH=34 35 | GTH=35 36 | NOT_EQ=36 37 | NOT=37 38 | LET=38 39 | GET=39 40 | SEMI=40 41 | COMMA=41 42 | DOT=42 43 | COLLATE=43 44 | USING=44 45 | INDEX=45 46 | BETWEEN=46 47 | POLYPHONIC=47 48 | HAPPINESSINDEX=48 49 | SADNESSINDEX=49 50 | POWERINDEX=50 51 | MAXMELODICREPREATINGFACTOR=51 52 | ID=52 53 | INT=53 54 | DOUBLE=54 55 | DATABASENAME=55 56 | NEWLINE=56 57 | WS=57 58 | USER_VAR=58 59 | 'select'=1 60 | 'midi'=2 61 | 'sheet'=3 62 | 'mp3'=4 63 | 'musicxml'=5 64 | 'on'=6 65 | 'from'=7 66 | 'where'=8 67 | 'is'=11 68 | 'null'=12 69 | 'in'=13 70 | 'true'=14 71 | 'false'=15 72 | '+'=18 73 | '-'=19 74 | '~'=20 75 | '|'=21 76 | '&'=22 77 | '^'=23 78 | 'binary'=24 79 | 'escape'=25 80 | '*'=26 81 | ')'=27 82 | '('=28 83 | ']'=29 84 | '['=30 85 | ':'=31 86 | '.*'=32 87 | '='=33 88 | '<'=34 89 | '>'=35 90 | '!='=36 91 | 'not'=37 92 | '<='=38 93 | '>='=39 94 | ';'=40 95 | ','=41 96 | '.'=42 97 | 'collate'=43 98 | 'using'=44 99 | 'index'=45 100 | 'between'=46 101 | 'polyphonic'=47 102 | 'happinessindex'=48 103 | 'sadnessindex'=49 104 | 'powerindex'=50 105 | 'maxmelodicrepeatingfactor'=51 106 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/modulo7SQL/Modulo7QueryComponents.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.modulo7SQL; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by asanyal on 9/21/15. 8 | * 9 | * A data structure which contains query components being parsed 10 | */ 11 | public class Modulo7QueryComponents { 12 | 13 | // Input types to be queried 14 | private Set inputs; 15 | 16 | // Expression List to be parsed 17 | private List exprList; 18 | 19 | // Expr oprs like and/or in between expr List 20 | private List exprOprList; 21 | 22 | // DB Name in the query components 23 | private String dbName; 24 | 25 | /** 26 | * Basic constructor 27 | * 28 | * @param inputs 29 | * @param exprList 30 | * @param exprOprList 31 | * @param dbName 32 | */ 33 | public Modulo7QueryComponents(final Set inputs, final List exprList, final List exprOprList, final String dbName) { 34 | this.inputs = inputs; 35 | this.exprList = exprList; 36 | this.exprOprList = exprOprList; 37 | if (dbName != null) { 38 | this.dbName = "default_database"; 39 | } 40 | 41 | assert (exprList.size() - 1 == exprOprList.size()); 42 | } 43 | 44 | public Set getInputs() { 45 | return inputs; 46 | } 47 | 48 | public List getExprList() { 49 | return exprList; 50 | } 51 | 52 | public List getExprOprList() { 53 | return exprOprList; 54 | } 55 | 56 | public String getDbName() { 57 | return dbName; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/playback/MusicXMLPlayback.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.playback; 2 | 3 | import nu.xom.ParsingException; 4 | import org.apache.log4j.Logger; 5 | import org.jfugue.integration.MusicXmlParser_R; 6 | import org.jfugue.pattern.Pattern; 7 | import org.jfugue.player.Player; 8 | import org.staccato.StaccatoParserListener; 9 | 10 | import javax.xml.parsers.ParserConfigurationException; 11 | import java.io.IOException; 12 | 13 | /** 14 | * Created by asanyal on 10/22/15. 15 | * 16 | * Playback for music xml 17 | */ 18 | public class MusicXMLPlayback implements AbstractPlayBack { 19 | 20 | // File location of music xml file 21 | private String musicXMLFileName; 22 | 23 | // Logger for music xml playback 24 | private static final Logger logger = Logger.getLogger(MusicXMLPlayback.class); 25 | 26 | /** 27 | * Default constructor 28 | * @param fileName 29 | */ 30 | public MusicXMLPlayback(final String fileName) { 31 | this.musicXMLFileName = fileName; 32 | } 33 | 34 | @Override 35 | public void play() { 36 | try { 37 | MusicXmlParser_R parser = new MusicXmlParser_R(); 38 | StaccatoParserListener listener = new StaccatoParserListener(); 39 | parser.addParserListener(listener); 40 | parser.parse(musicXMLFileName); 41 | Player player = new Player(); 42 | final Pattern musicXMLPattern = listener.getPattern(); 43 | player.play(musicXMLPattern); 44 | } catch (ParserConfigurationException | IOException | ParsingException e) { 45 | logger.error(e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/genericsimilarity/GeneralMaximalVoiceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.genericsimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongSimilarity; 4 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | 8 | /** 9 | * Created by asanyal on 10/13/15. 10 | * 11 | * Generic similarity where we do not care about unequal lengths of melodies 12 | */ 13 | public class GeneralMaximalVoiceSimilarity implements AbstractSongSimilarity { 14 | 15 | // The internal voice similarity measure 16 | private T internalVoiceSimilarity; 17 | 18 | /** 19 | * Basic constructor for generic maximal similarity 20 | * @param similarityMeasure (The internal similarity measure used inside generic maximal voice similarity) 21 | */ 22 | public GeneralMaximalVoiceSimilarity(final T similarityMeasure) { 23 | internalVoiceSimilarity = similarityMeasure; 24 | } 25 | 26 | @Override 27 | public double getSimilarity(Song first, Song second) { 28 | double bestSim = -Double.MAX_VALUE; 29 | 30 | for (final Voice firstVoice : first.getVoices()) { 31 | for (final Voice secondVoice : second.getVoices()) { 32 | final double currSim = internalVoiceSimilarity.getSimilarity(firstVoice, secondVoice); 33 | bestSim = Math.max(bestSim, currSim); 34 | } 35 | } 36 | 37 | return bestSim; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/LongestChordProgression.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractStatistic; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | 8 | /** 9 | * Created by asanyal on 10/25/15. 10 | * 11 | * The longest chord progression seen in a song in any voice 12 | * This is a coarse measure on how harmonically dominated the song is 13 | * (typically occurs for songs with accompanyments with large number of chords) 14 | * 15 | * This measure does not take into account repeating chord sequences which is a separate measure in 16 | * its own right 17 | */ 18 | public class LongestChordProgression implements AbstractStatistic { 19 | 20 | @Override 21 | public Double getStatistic(final Song song) { 22 | double longestSeenSoFar = 0; 23 | 24 | for (final Voice voice : song.getVoices()) { 25 | 26 | int bestSeen = 0; 27 | 28 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 29 | if (instant.isChord()) { 30 | bestSeen += 1; 31 | } else { 32 | longestSeenSoFar = Math.max(longestSeenSoFar, bestSeen); 33 | // Rest best Seen to 0, the reason is, chord progression seen ends here, so reset it 34 | bestSeen = 0; 35 | } 36 | } 37 | } 38 | 39 | return longestSeenSoFar; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/datastructures/VoicePitchList.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.datastructures; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by asanyal on 9/4/15. 12 | * 13 | * This data structure contains pitches in sequence that occur in a voice 14 | * along with a tokenization scheme for different chords 15 | */ 16 | public class VoicePitchList { 17 | 18 | // Pitches on the voices in sequence 19 | private List pitchesInSequenceOfVoice = new ArrayList<>(); 20 | 21 | /** 22 | * Computes the voice pitches in sequence 23 | * @param voice 24 | */ 25 | public void computeVoicePitchSet(final Voice voice) throws Modulo7WrongNoteType { 26 | 27 | // Iterate through the voice instants and acquire the necessary 28 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 29 | pitchesInSequenceOfVoice.add(instant.getTokenRepresentation()); 30 | } 31 | } 32 | 33 | /** 34 | * Getter for pitches in sequence of voice 35 | * @return 36 | */ 37 | private List getPitchesInSequenceOfVoice() { 38 | return pitchesInSequenceOfVoice; 39 | } 40 | 41 | /** 42 | * Length of the voice pitch sequence 43 | * @return 44 | */ 45 | public int length() { 46 | return pitchesInSequenceOfVoice.size(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/parsertests/ComparisonsTest.java: -------------------------------------------------------------------------------- 1 | package parsertests; 2 | 3 | import com.echonest.api.v4.EchoNestException; 4 | import com.modulo7.acoustics.EchoNestBasicMP3Analyzer; 5 | import com.modulo7.acoustics.MidiToSongConverter; 6 | import com.modulo7.common.exceptions.Modulo7NoSuchFileOrDirectoryException; 7 | import com.modulo7.common.interfaces.AbstractAnalyzer; 8 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import javax.sound.midi.InvalidMidiDataException; 13 | import java.io.IOException; 14 | 15 | /** 16 | * Created by asanyal on 9/6/15. 17 | * 18 | * Basic comparison tests for midi and mp3 on data that is perfectly aligned 19 | * 20 | * In general this class will include checks on different sources that are aligned 21 | */ 22 | public class ComparisonsTest { 23 | 24 | @Test 25 | public void midiMp3Comparison() throws EchoNestException, Modulo7NoSuchFileOrDirectoryException, InvalidMidiDataException, IOException { 26 | 27 | final String mp3Location = "./src/test/testdata/mp3/Bach_SMD.mp3"; 28 | AbstractAnalyzer mp3Analyzer = new EchoNestBasicMP3Analyzer(mp3Location); 29 | final Song mp3Song = mp3Analyzer.getSongRepresentation(); 30 | 31 | final String midiLocation = "./src/test/testdata/midi/Bach_SMD.mid"; 32 | AbstractAnalyzer midiAnalyzer = new MidiToSongConverter(midiLocation); 33 | final Song midiSong = midiAnalyzer.getSongRepresentation(); 34 | 35 | // Since the tracks are aligned the number of voices should be the same 36 | Assert.assertEquals(mp3Song.getNumVoices(), midiSong.getNumVoices()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/voicevectors/VoiceIntervalPitchVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.voicevectors; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 5 | import com.modulo7.common.interfaces.AbstractVoiceVector; 6 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 7 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.VoiceIntervalPitchList; 8 | import org.apache.log4j.Logger; 9 | 10 | /** 11 | * Created by asanyal on 9/8/15. 12 | * 13 | * Interval pitch vector representation of a given voice 14 | */ 15 | public class VoiceIntervalPitchVector implements AbstractVoiceVector { 16 | 17 | // Pitch List element in the voice interval pitch vector 18 | private VoiceIntervalPitchList pitchList = new VoiceIntervalPitchList(); 19 | 20 | // Logger for voice interval pitch vector representation 21 | private static final Logger logger = Logger.getLogger(VoiceIntervalPitchVector.class); 22 | 23 | @Override 24 | public int getVectorLength() { 25 | return pitchList.length(); 26 | } 27 | 28 | @Override 29 | public void computeVectorRepresentation(final Voice voice) { 30 | try { 31 | pitchList.computeVoicePitchSet(voice); 32 | } catch (Modulo7WrongNoteType | Modulo7BadIntervalException e) { 33 | logger.error(e.getMessage()); 34 | } 35 | } 36 | 37 | @Override 38 | public VoiceIntervalPitchList getInternalRepresentation() { 39 | return pitchList; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/othersources/NoteAndIsChordDual.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.othersources; 2 | 3 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 4 | import com.modulo7.musicstatmodels.representation.buildingblocks.NoteDuration; 5 | 6 | /** 7 | * A helper class for crunching chords in music xml in basic XML 8 | * 9 | * This class contains a note as it appears in music xml note tag and 10 | * a boolean which states whether note tag is also tagged with chord tag 11 | */ 12 | public class NoteAndIsChordDual { 13 | 14 | private Note note; 15 | 16 | private boolean isChordElement; 17 | 18 | private double duration; 19 | 20 | private NoteDuration theoreticalDuration = NoteDuration.UNKNOWN; 21 | 22 | public NoteAndIsChordDual(final Note note, final boolean isChordElement) { 23 | this.note = note; 24 | this.isChordElement = isChordElement; 25 | } 26 | 27 | /** 28 | * Full constructor 29 | * @param note 30 | * @param isChordElement 31 | * @param duration 32 | * @param theoreticalDuration 33 | */ 34 | public NoteAndIsChordDual(final Note note, final boolean isChordElement, final double duration, final NoteDuration theoreticalDuration) { 35 | this.note = note; 36 | this.isChordElement = isChordElement; 37 | this.duration = duration; 38 | this.theoreticalDuration = theoreticalDuration; 39 | } 40 | 41 | public Note getNote() { 42 | return note; 43 | } 44 | 45 | public boolean isChordElement() { 46 | return isChordElement; 47 | } 48 | 49 | public double getDuration() { 50 | return duration; 51 | } 52 | 53 | public NoteDuration getTheoreticalDuration() { 54 | return theoreticalDuration; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/representation/buildingblocks/NoteDuration.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.representation.buildingblocks; 2 | 3 | /** 4 | * Created by asanyal on 8/31/15. 5 | * 6 | * A mathematically precise duration element 7 | * 8 | * If a voice instant contains this element, its a more precise 9 | * representation than what is actually played (the double duration element) 10 | * 11 | * Information taken from http://www.musicxml.com/UserManuals/MusicXML/Content/ST-MusicXML-note-type-value.htm 12 | */ 13 | public enum NoteDuration { 14 | WHOLE, 15 | HALF, 16 | QUARTER, 17 | EIGHTH, 18 | SIXTEENTH, 19 | THIRTYSECOND, 20 | SIXTYFOURTH, 21 | UNKNOWN; 22 | 23 | NoteDuration() { 24 | 25 | } 26 | 27 | /** 28 | * Static getter for note duration element from the note duration string argument 29 | * 30 | * Ususally found in Music XML files 31 | * 32 | * @param noteDuration 33 | * @return 34 | */ 35 | public static NoteDuration getNoteDurationFromMusicXML(final String noteDuration) { 36 | if (noteDuration.equalsIgnoreCase("whole")) 37 | return WHOLE; 38 | else if (noteDuration.equalsIgnoreCase("half")) 39 | return HALF; 40 | else if (noteDuration.equalsIgnoreCase("quarter")) 41 | return QUARTER; 42 | else if (noteDuration.equalsIgnoreCase("eighth")) 43 | return EIGHTH; 44 | else if (noteDuration.equalsIgnoreCase("16th")) 45 | return SIXTEENTH; 46 | else if (noteDuration.equalsIgnoreCase("32nd")) 47 | return THIRTYSECOND; 48 | else if (noteDuration.equalsIgnoreCase("64th")) 49 | return SIXTYFOURTH; 50 | else 51 | return UNKNOWN; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/musicstatmodelstests/MaxMelodicRepeatingFactorTest.java: -------------------------------------------------------------------------------- 1 | package musicstatmodelstests; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 4 | import com.modulo7.common.exceptions.Modulo7InvalidVoiceInstantSizeException; 5 | import com.modulo7.common.interfaces.AbstractStatistic; 6 | import com.modulo7.common.utils.MusicSources; 7 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 8 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 9 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 10 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 11 | import com.modulo7.musicstatmodels.statistics.MaxMelodicRepeatingFactor; 12 | import org.junit.Assert; 13 | import org.junit.Test; 14 | 15 | /** 16 | * Created by asanyal on 9/24/15. 17 | * 18 | * Test cases for max melodic repeating factor 19 | */ 20 | public class MaxMelodicRepeatingFactorTest { 21 | 22 | @Test 23 | public void maxMelodicRepeatingFactor() throws Modulo7InvalidVoiceInstantSizeException, Modulo7BadNoteException { 24 | AbstractStatistic maxMelodicRepeatingFactor = new MaxMelodicRepeatingFactor(); 25 | 26 | Voice testVoice = new Voice(); 27 | testVoice.addVoiceInstant(new VoiceInstant(Note.A0)); 28 | testVoice.addVoiceInstant(new VoiceInstant(Note.A0)); 29 | testVoice.addVoiceInstant(new VoiceInstant(Note.C0)); 30 | testVoice.addVoiceInstant(new VoiceInstant(Note.A0)); 31 | testVoice.addVoiceInstant(new VoiceInstant(Note.A0)); 32 | 33 | Song testSong = new Song(testVoice, MusicSources.UNKNOWN); 34 | 35 | Double repeatingFraction = maxMelodicRepeatingFactor.getStatistic(testSong); 36 | 37 | Assert.assertEquals(repeatingFraction, 0.4, 0.0); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/antlr/Modulo7SQLBase.g4: -------------------------------------------------------------------------------- 1 | lexer grammar Modulo7SQLBase; 2 | 3 | @header { 4 | package com.modulo7.modulo7SQL; 5 | } 6 | 7 | SELECT: 'select'; 8 | MIDI: 'midi'; 9 | SHEET: 'sheet'; 10 | MP3: 'mp3'; 11 | MUSICXML: 'musicxml'; 12 | ON : 'on'; 13 | FROM: 'from'; 14 | WHERE: 'where'; 15 | AND: 'and' | '&&'; 16 | OR: 'or' | '||'; 17 | IS: 'is'; 18 | NULL: 'null'; 19 | IN: 'in'; 20 | TRUE: 'true'; 21 | FALSE: 'false'; 22 | DIVIDE : 'div' | '/' ; 23 | MOD: 'mod' | '%' ; 24 | PLUS : '+' ; 25 | MINUS : '-' ; 26 | NEGATION: '~' ; 27 | VERTBAR : '|' ; 28 | BITAND : '&' ; 29 | POWER_OP: '^' ; 30 | BINARY: 'binary'; 31 | ESCAPE: 'escape'; 32 | ASTERISK: '*' ; 33 | RPAREN : ')' ; 34 | LPAREN : '(' ; 35 | RBRACK : ']' ; 36 | LBRACK : '[' ; 37 | COLON : ':' ; 38 | ALL_FIELDS : '.*' ; 39 | EQ: '='; 40 | LTH: '<'; 41 | GTH: '>'; 42 | NOT_EQ: '!='; 43 | NOT: 'not'; 44 | LET: '<='; 45 | GET: '>='; 46 | SEMI: ';'; 47 | COMMA: ','; 48 | DOT: '.'; 49 | COLLATE: 'collate'; 50 | USING: 'using'; 51 | INDEX: 'index'; 52 | BETWEEN: 'between'; 53 | 54 | POLYPHONIC: 'polyphonic'; 55 | 56 | HAPPINESSINDEX : 'happinessindex'; 57 | SADNESSINDEX : 'sadnessindex'; 58 | POWERINDEX : 'powerindex'; 59 | MAXMELODICREPREATINGFACTOR: 'maxmelodicrepeatingfactor'; 60 | 61 | ID: ('a'..'z' | 'A' .. 'Z' | '_')+ ; 62 | INT: '0'..'9'+ ; 63 | DOUBLE : '0'..'9'+'.''0'..'9'+ ; 64 | DATABASENAME: ('a'..'z' | 'A' .. 'Z' | '_')+ ; 65 | 66 | NEWLINE: '\r' ? '\n' -> skip; 67 | WS: (' ' | '\t' | '\n' | '\r')+ -> skip; 68 | 69 | USER_VAR: 70 | '@' (USER_VAR_SUBFIX1 | USER_VAR_SUBFIX2 | USER_VAR_SUBFIX3 | USER_VAR_SUBFIX4) 71 | ; 72 | 73 | fragment USER_VAR_SUBFIX1: ( '`' (~'`' )+ '`' ) ; 74 | fragment USER_VAR_SUBFIX2: ( '\'' (~'\'')+ '\'' ) ; 75 | fragment USER_VAR_SUBFIX3: ( '\"' (~'\"')+ '\"' ) ; 76 | fragment USER_VAR_SUBFIX4: ( 'A'..'Z' | 'a'..'z' | '_' | '$' | '0'..'9' | DOT )+ ; -------------------------------------------------------------------------------- /src/main/java/com/modulo7/cli/Modulo7CLIChoice.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.cli; 2 | 3 | /** 4 | * Created by asanyal on 9/17/15. 5 | * 6 | * The set of choices that are present for Modulo7 7 | * an enum makes it easier to manage the choices of the query set 8 | * exposed to the consumer 9 | */ 10 | public enum Modulo7CLIChoice { 11 | 12 | RET_SONGS_FOR_GIVEN_ARTIST(1), 13 | RANK_ON_SIMILARITY_ORDER(2), 14 | RET_SONGS_FOR_GIVEN_KEY_SIGNATURE(3), 15 | RET_SONGS_FOR_GIVEN_TIME_SIGNATURE(4), 16 | RET_LYRICS_GIVEN_SONG(5), 17 | LIST_NUM_SONGS_INDEXED(6), 18 | INPUT_CUSTOM_QUERY(7), 19 | LYRICS_QUERY(8), 20 | MELODIC_ALIGNMENT_ANALYSIS(9), 21 | SERIALIZE_DATABASE(10), 22 | PLAYBACK_SONG(11), 23 | EXIT(12), 24 | INVALID_CHOICE(-1); 25 | 26 | final int choice; 27 | 28 | Modulo7CLIChoice(int choice) { 29 | this.choice = choice; 30 | } 31 | 32 | /** 33 | * Parse an integer choice and then returns the enum variant, easier for readability 34 | * @param choiceNum 35 | * @return 36 | */ 37 | public static Modulo7CLIChoice parseChoice(final int choiceNum) { 38 | switch (choiceNum) { 39 | case 1: return RET_SONGS_FOR_GIVEN_ARTIST; 40 | case 2: return RANK_ON_SIMILARITY_ORDER; 41 | case 3: return RET_SONGS_FOR_GIVEN_KEY_SIGNATURE; 42 | case 4: return RET_SONGS_FOR_GIVEN_TIME_SIGNATURE; 43 | case 5: return RET_LYRICS_GIVEN_SONG; 44 | case 6: return LIST_NUM_SONGS_INDEXED; 45 | case 7: return INPUT_CUSTOM_QUERY; 46 | case 8: return LYRICS_QUERY; 47 | case 9: return MELODIC_ALIGNMENT_ANALYSIS; 48 | case 10: return SERIALIZE_DATABASE; 49 | case 11: return PLAYBACK_SONG; 50 | case 12: return EXIT; 51 | default: return INVALID_CHOICE; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/test/testdata/lyrics/stairway_to_heaven: -------------------------------------------------------------------------------- 1 | There's a lady who's sure all that glitters is gold 2 | And she's buying a stairway to heaven. 3 | When she gets there she knows, if the stores are all closed 4 | With a word she can get what she came for. 5 | Ooh, ooh, and she's buying a stairway to heaven. 6 | 7 | There's a sign on the wall but she wants to be sure 8 | 'Cause you know sometimes words have two meanings. 9 | In a tree by the brook, there's a songbird who sings, 10 | Sometimes all of our thoughts are misgiven. 11 | 12 | Ooh, it makes me wonder, 13 | Ooh, it makes me wonder. 14 | 15 | There's a feeling I get when I look to the west, 16 | And my spirit is crying for leaving. 17 | In my thoughts I have seen rings of smoke through the trees, 18 | And the voices of those who stand looking. 19 | 20 | Ooh, it makes me wonder, 21 | Ooh, it really makes me wonder. 22 | 23 | And it's whispered that soon, if we all call the tune, 24 | Then the piper will lead us to reason. 25 | And a new day will dawn for those who stand long, 26 | And the forests will echo with laughter. 27 | 28 | If there's a bustle in your hedgerow, don't be alarmed now, 29 | It's just a spring clean for the May queen. 30 | Yes, there are two paths you can go by, but in the long run 31 | There's still time to change the road you're on. 32 | And it makes me wonder. 33 | 34 | Your head is humming and it won't go, in case you don't know, 35 | The piper's calling you to join him, 36 | Dear lady, can you hear the wind blow, and did you know 37 | Your stairway lies on the whispering wind? 38 | 39 | And as we wind on down the road 40 | Our shadows taller than our soul. 41 | There walks a lady we all know 42 | Who shines white light and wants to show 43 | How everything still turns to gold. 44 | And if you listen very hard 45 | The tune will come to you at last. 46 | When all are one and one is all 47 | To be a rock and not to roll. 48 | 49 | And she's buying a stairway to heaven. -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/songvectors/PitchVector.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.common.interfaces.AbstractSongVector; 5 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 6 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 7 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.VoicePitchList; 8 | import org.apache.log4j.Logger; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | /** 14 | * Created by asanyal on 9/4/15. 15 | * 16 | * The pitch vector is a vector space representation with the raw pitches 17 | * as a sequence of strings / characters in sequence 18 | * 19 | * This pitch vector is a generalization of the pitch vector in Similie which 20 | * is per melody, pitch vector here is with respect to entire song 21 | */ 22 | public class PitchVector implements AbstractSongVector> { 23 | 24 | // Voice pitch list 25 | private Set voicePitchListSet = new HashSet<>(); 26 | 27 | // Logger for the pitch vector class 28 | private static final Logger logger = Logger.getLogger(PitchVector.class); 29 | 30 | @Override 31 | public void computeVectorRepresentation(final Song song) { 32 | 33 | for (final Voice voice : song.getVoices()) { 34 | VoicePitchList list = new VoicePitchList(); 35 | try { 36 | list.computeVoicePitchSet(voice); 37 | voicePitchListSet.add(list); 38 | } catch (Modulo7WrongNoteType e) { 39 | logger.error(e.getMessage()); 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public Set getInternalRepresentation() { 46 | return voicePitchListSet; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/genreestimation/GenreEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.genreestimation; 2 | 3 | import com.modulo7.pureresearch.lastfm.SongBagLyricsGenreMap; 4 | import com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim.BOWSimilarityChoices; 5 | 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by asanyal on 12/22/15. 12 | * 13 | * Skeletal genre estimation class 14 | * 15 | * All implementations must implement this class 16 | */ 17 | public abstract class GenreEstimation { 18 | 19 | // A set of song bagged lyrics and meta data mapped 20 | protected Set lyricsMappedGenreEntries; 21 | 22 | // Train set split of the Tag Estimation algorithm 23 | protected Set trainSet; 24 | 25 | // The test set split of the tag estimation algorithm 26 | protected Set testSet; 27 | 28 | // All the seen genres 29 | public Set allSeenGenres = new HashSet<>(); 30 | 31 | // Choice of bag of words similarity 32 | protected static final BOWSimilarityChoices SIM_CHOICE = BOWSimilarityChoices.COSINE_SIMILARITY; 33 | 34 | /** 35 | * Tag estimator default constructor 36 | * 37 | * @param testSet 38 | * @param trainSet 39 | */ 40 | public GenreEstimation(final Set testSet, final Set trainSet) { 41 | this.testSet = testSet; 42 | this.trainSet = trainSet; 43 | } 44 | 45 | /** 46 | * Gets the estimated tags for a given 47 | * @return 48 | */ 49 | public abstract Map> getEstimatedGenres(); 50 | 51 | /** 52 | * Gets all the seen genres 53 | * @return 54 | */ 55 | public Set getAllSeenGenres() { 56 | return allSeenGenres; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/SadnessIndex.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongVector; 4 | import com.modulo7.common.interfaces.AbstractStatistic; 5 | import com.modulo7.musicstatmodels.musictheorymodels.IntervalQuantity; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalHistogramData; 8 | import com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors.TonalHistogram; 9 | 10 | /** 11 | * Created by asanyal on 8/29/15. 12 | * 13 | * Similar to power index but counts the minor intervals and divides by total number 14 | * 15 | * Similar weighting scheme could be done as power index 16 | */ 17 | public class SadnessIndex implements AbstractStatistic { 18 | /** 19 | * Default constructor of power index 20 | */ 21 | public SadnessIndex() { 22 | 23 | } 24 | 25 | /** 26 | * Gets the perfect intervals vs total intervals ratio 27 | * @param song 28 | * @return 29 | */ 30 | @Override 31 | public Double getStatistic(final Song song) { 32 | AbstractSongVector tonalHistogram = new TonalHistogram(); 33 | tonalHistogram.computeVectorRepresentation(song); 34 | TonalHistogramData histogramData = tonalHistogram.getInternalRepresentation(); 35 | 36 | final int totalSum = histogramData.getHistogramTotalSum(); 37 | 38 | int minorSum = 0; 39 | 40 | // Add perfect intervals to perfect sum 41 | minorSum += histogramData.getCountForInterval(IntervalQuantity.MINOR_SECOND); 42 | minorSum += histogramData.getCountForInterval(IntervalQuantity.MINOR_THIRD); 43 | minorSum += histogramData.getCountForInterval(IntervalQuantity.MINOR_SIXTH); 44 | minorSum += histogramData.getCountForInterval(IntervalQuantity.MINOR_SEVENTH); 45 | 46 | return (double)(minorSum) / totalSum; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/preprocessing/VoiceToMelodyConversion.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.preprocessing; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 4 | import com.modulo7.common.exceptions.Modulo7InvalidVoiceInstantSizeException; 5 | import com.modulo7.musicstatmodels.representation.buildingblocks.ChordQuality; 6 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 7 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 8 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 9 | import org.apache.commons.lang3.SerializationUtils; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Created by asanyal on 9/21/15. 15 | * 16 | * Preprocessing step to convert a voice to a pure melodic transcription 17 | * This step is necessary in pure melodic similarity measures and statistic 18 | * computations 19 | */ 20 | public class VoiceToMelodyConversion { 21 | 22 | /** 23 | * Method that converts a generic voice to a pure melody by replacing chords with their root 24 | * notes in a voice 25 | * 26 | * @param inputVoice 27 | * @return 28 | * @throws Modulo7InvalidVoiceInstantSizeException 29 | */ 30 | public static Voice melodyConversion(final Voice inputVoice) throws Modulo7InvalidVoiceInstantSizeException, Modulo7BadNoteException { 31 | 32 | Voice copyOfVoice = SerializationUtils.clone(inputVoice); 33 | List voiceSequence = copyOfVoice.getVoiceSequence(); 34 | 35 | for (int i = 0; i < voiceSequence.size(); i++) { 36 | VoiceInstant voiceInstant = voiceSequence.get(i); 37 | 38 | if (voiceInstant.isChord()) { 39 | Note rootNote = ChordQuality.getRootNoteFromChord(voiceInstant.getAllNotesofInstant()); 40 | VoiceInstant newInstant = new VoiceInstant(rootNote); 41 | 42 | voiceSequence.set(i, newInstant); 43 | } 44 | } 45 | 46 | return copyOfVoice; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/antlr/Modulo7SQL.g4: -------------------------------------------------------------------------------- 1 | grammar Modulo7SQL; 2 | 3 | // Check out the examples from https://github.com/antlr/grammars-v4/blob/master/mysql/MySQL.g4 4 | 5 | options { 6 | tokenVocab = Modulo7SQLBase; 7 | 8 | // antlr will generate java lexer and parser 9 | language = Java; 10 | 11 | // generated parser should create abstract syntax tree 12 | output = AST; 13 | } 14 | 15 | @header { 16 | package com.modulo7.modulo7SQL; 17 | } 18 | 19 | select_clause: 20 | select_key 21 | input_list_clause 22 | (from_clause)? 23 | (where_clause)? 24 | SEMI 25 | ; 26 | 27 | from_clause: 28 | FROM table_name 29 | ; 30 | 31 | table_name: 32 | ID 33 | ; 34 | 35 | input_name: 36 | MIDI 37 | | SHEET 38 | | MP3 39 | | MUSICXML; 40 | 41 | column_name_alias: 42 | ID 43 | ; 44 | 45 | index_name: 46 | ID 47 | ; 48 | 49 | input_list_clause: 50 | input_name (COMMA input_name)* 51 | ; 52 | 53 | select_key: 54 | SELECT 55 | ; 56 | 57 | where_clause: 58 | WHERE expression 59 | ; 60 | 61 | expression: 62 | simple_expression (expr_op simple_expression)* 63 | ; 64 | 65 | element: 66 | INT | DOUBLE 67 | ; 68 | 69 | right_element: 70 | element 71 | ; 72 | 73 | left_element: 74 | element 75 | ; 76 | 77 | target_element: 78 | element 79 | ; 80 | 81 | relational_op: 82 | EQ | LTH | GTH | NOT_EQ ; 83 | 84 | expr_op: 85 | AND | OR | NOT ; 86 | 87 | between_op: 88 | BETWEEN 89 | ; 90 | 91 | is_or_is_not: 92 | IS | IS NOT 93 | ; 94 | 95 | either_true_or_false: 96 | TRUE | FALSE 97 | ; 98 | 99 | simple_expression: 100 | criteria is_or_is_not either_true_or_false | 101 | statistic relational_op element | 102 | statistic between_op left_element AND right_element 103 | ; 104 | 105 | criteria: 106 | POLYPHONIC 107 | ; 108 | 109 | statistic: 110 | HAPPINESSINDEX | 111 | SADNESSINDEX | 112 | POWERINDEX | 113 | MAXMELODICREPREATINGFACTOR 114 | ; -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/HappinessIndex.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongVector; 4 | import com.modulo7.common.interfaces.AbstractStatistic; 5 | import com.modulo7.musicstatmodels.musictheorymodels.IntervalQuantity; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalHistogramData; 8 | import com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors.TonalHistogram; 9 | 10 | /** 11 | * Created by asanyal on 8/29/15. 12 | * 13 | * Similar to power index but counts the major intervals and divides by total number 14 | * 15 | * Similar weighting scheme could be done as power index 16 | */ 17 | public class HappinessIndex implements AbstractStatistic { 18 | /** 19 | * Default constructor of power index 20 | */ 21 | public HappinessIndex() { 22 | 23 | } 24 | 25 | /** 26 | * Gets the perfect intervals vs total intervals ratio 27 | * @param song 28 | * @return 29 | */ 30 | @Override 31 | public Double getStatistic(final Song song) { 32 | AbstractSongVector tonalHistogram = new TonalHistogram(); 33 | tonalHistogram.computeVectorRepresentation(song); 34 | TonalHistogramData histogramData = tonalHistogram.getInternalRepresentation(); 35 | 36 | final int totalSum = histogramData.getHistogramTotalSum(); 37 | 38 | int majorSum = 0; 39 | 40 | // Add perfect intervals to perfect sum 41 | majorSum += histogramData.getCountForInterval(IntervalQuantity.MAJOR_SECOND); 42 | majorSum += histogramData.getCountForInterval(IntervalQuantity.MAJOR_THIRD); 43 | majorSum += histogramData.getCountForInterval(IntervalQuantity.MAJOR_SIXTH); 44 | majorSum += histogramData.getCountForInterval(IntervalQuantity.MAJOR_SEVENTH); 45 | 46 | return (double)(majorSum) / totalSum; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/datastructures/PitchDurationHistogramData.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.datastructures; 2 | 3 | import com.modulo7.common.utils.Modulo7Globals; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * Created by asanyal on 10/2/15. 9 | * 10 | * Similar to tonal duration histogram, but for individual pitches 11 | */ 12 | public class PitchDurationHistogramData { 13 | 14 | // Internal intervalHistogram representation 15 | private Map pitchHistogram = new HashMap<>(); 16 | 17 | /** 18 | * Tonal Histogram scratch representation 19 | */ 20 | public PitchDurationHistogramData() { 21 | for (final String pitch : Modulo7Globals.NOTE_NAMES_ONLY_SHARPS) { 22 | pitchHistogram.put(pitch, 0.0); 23 | } 24 | } 25 | 26 | /** 27 | * Gets an array representation of the vectorized data 28 | * @return 29 | */ 30 | public List getArrayRepresentation() { 31 | Double[] array = new Double[12]; 32 | 33 | for (Map.Entry histogramElem : pitchHistogram.entrySet()) { 34 | 35 | final String note = histogramElem.getKey(); 36 | final int position = Modulo7Globals.getIndexOfNote(note); 37 | array[position] = histogramElem.getValue(); 38 | } 39 | 40 | List values = Arrays.asList(array); 41 | 42 | Collections.rotate(values, -3); 43 | 44 | return values; 45 | } 46 | 47 | /** 48 | * Gets a durational data from histogram for a particular note 49 | * @param interval 50 | * @return 51 | */ 52 | public Double getData(final String interval) { 53 | return pitchHistogram.get(interval); 54 | } 55 | 56 | /** 57 | * Sets durational data in histogram for a particular note 58 | * @param noteVal 59 | * @param value 60 | */ 61 | public void setData(final String noteVal, final double value) { 62 | pitchHistogram.put(noteVal, value); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/cache/Modulo7Cache.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.cache; 2 | 3 | import org.apache.commons.jcs.JCS; 4 | 5 | import java.util.LinkedHashMap; 6 | import java.util.LinkedHashSet; 7 | import java.util.Set; 8 | 9 | import org.apache.commons.jcs.access.CacheAccess; 10 | 11 | /** 12 | * Created by asanyal on 10/28/15. 13 | * 14 | * Caching results for maximum performance for Modulo7 given a set of queries 15 | */ 16 | public class Modulo7Cache { 17 | 18 | // Gets a class level cache, a singleton for all instance (although by design its only used in Modulo7 CLI) 19 | private static final CacheAccess cache = JCS.getInstance(Modulo7Cache.class.getName()); 20 | 21 | /** 22 | * Method to cache custom 23 | * 24 | * @param query 25 | * @param queryResults 26 | */ 27 | public void cacheQueryResults(final String query, final Set queryResults) { 28 | final Modulo7CustomQueryCacheObject object = new Modulo7CustomQueryCacheObject(queryResults); 29 | cache.put(query, object); 30 | } 31 | 32 | /** 33 | * Method to cache similarity query 34 | * 35 | * @param query 36 | * @param queryResults 37 | */ 38 | public void cacheQueryResults(final String query, final LinkedHashMap queryResults) { 39 | final Modulo7SimilarityResultCacheObject object = new Modulo7SimilarityResultCacheObject(queryResults); 40 | cache.put(query, object); 41 | } 42 | 43 | /** 44 | * Query caching system 45 | * 46 | * @param query 47 | * @return 48 | */ 49 | public Object getCachedResults(final String query) { 50 | Modulo7CacheObject results = cache.get(query); 51 | 52 | if (results != null) { 53 | return results.getQueryResults(); 54 | } else { 55 | return null; 56 | } 57 | } 58 | 59 | /** 60 | * A powerful method that invalidates the cache completely 61 | */ 62 | public void invalidateCache() { 63 | cache.clear(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/contour/ContourSongRep.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.contour; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 5 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 6 | import com.modulo7.common.interfaces.AbstractContour; 7 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 8 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 9 | import org.apache.commons.lang3.SerializationUtils; 10 | 11 | import java.util.HashSet; 12 | 13 | /** 14 | * Created by asanyal on 10/4/15. 15 | * 16 | * The contourized representation of every voice in a song 17 | */ 18 | public class ContourSongRep { 19 | 20 | // The abstract contour representation internally 21 | private T internalContourRepresentation; 22 | 23 | /** 24 | * Init a contour song representation 25 | * @param internalContourRepresentation 26 | */ 27 | public ContourSongRep(final T internalContourRepresentation) { 28 | this.internalContourRepresentation = internalContourRepresentation; 29 | } 30 | 31 | /** 32 | * Gets the contourized representation of the a song (i.e contour for every voice) 33 | * 34 | * @param oldSong 35 | * @return 36 | * @throws Modulo7BadIntervalException 37 | * @throws Modulo7WrongNoteType 38 | */ 39 | public Song getContourizedSongRep(final Song oldSong) throws Modulo7BadIntervalException, Modulo7WrongNoteType, Modulo7BadNoteException { 40 | 41 | ContourGradient gradientRep = new ContourGradient<>(internalContourRepresentation); 42 | 43 | HashSet newVoiceSet = new HashSet<>(); 44 | for (final Voice voice : oldSong.getVoices()) { 45 | final Voice newVoice = gradientRep.getGradient(voice); 46 | newVoiceSet.add(newVoice); 47 | } 48 | 49 | return new Song(newVoiceSet, oldSong.getMetadata(), oldSong.getSource()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/utils/MusicSources.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.utils; 2 | 3 | import org.apache.commons.compress.compressors.FileNameUtil; 4 | import org.apache.commons.io.FilenameUtils; 5 | 6 | import java.util.Arrays; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by asanyal on 7/18/2015. 12 | * 13 | * This enumeration lists all the music sources that 14 | * can be acquired via modulo7 15 | * 16 | * As such a crawler can be configured to obtain a subset 17 | * of these sources for its processing or the database engine can 18 | * will be able to filter out only the songs that it needs based 19 | * on the extensions 20 | */ 21 | public enum MusicSources { 22 | 23 | // Acoustic sources 24 | MP3("mp3"), 25 | 26 | // Symbolic sources 27 | MUSIC_XML_FILE("musicxml"), 28 | MIDI("midi"), 29 | SHEET_MUSIC("sheet"), 30 | 31 | // Archaic research sources 32 | MSD("million_song_dataset"), 33 | 34 | // Unknown Source 35 | UNKNOWN("Unknown"); 36 | 37 | // String representation of source 38 | private String source; 39 | 40 | /** 41 | * Basic constructor for music sources 42 | * @param source 43 | */ 44 | MusicSources(final String source) { 45 | this.source = source; 46 | } 47 | 48 | // Supported file extensions for the modulo7 platform 49 | private static Set SUPPORTED_FILE_EXTENSIONS = new HashSet<>(Arrays.asList("mid", "midi", "mp3", "png", "pdf", "jpeg", "xml", "m7")); 50 | 51 | /** 52 | * Check if modulo7 allows a particular file extension for 53 | * @param fileName 54 | * @return 55 | */ 56 | public static boolean checkIfSupportedExtension(final String fileName) { 57 | final String fileExtension = FilenameUtils.getExtension(fileName); 58 | return SUPPORTED_FILE_EXTENSIONS.contains(fileExtension.toLowerCase()); 59 | } 60 | 61 | /** 62 | * Gets the string representation of the music source 63 | * @return 64 | */ 65 | public String getStringRepresentation() { 66 | return source; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/config/cache.ccf: -------------------------------------------------------------------------------- 1 | # DEFAULT CACHE REGION 2 | jcs.default=DC 3 | jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes 4 | jcs.default.cacheattributes.MaxObjects=1000 5 | jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache 6 | jcs.default.cacheattributes.UseMemoryShrinker=false 7 | jcs.default.cacheattributes.MaxMemoryIdleTime=3600 8 | jcs.default.cacheattributes.ShrinkerInterval=60 9 | jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes 10 | jcs.default.elementattributes.IsEternal=false 11 | jcs.default.elementattributes.MaxLife=21600 12 | jcs.default.elementattributes.IdleTime=1800 13 | jcs.default.elementattributes.IsSpool=true 14 | jcs.default.elementattributes.IsRemote=true 15 | jcs.default.elementattributes.IsLateral=true 16 | 17 | # PRE-DEFINED CACHE REGIONS 18 | jcs.region.testCache1=DC 19 | jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes 20 | jcs.region.testCache1.cacheattributes.MaxObjects=1000 21 | jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache 22 | jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false 23 | jcs.region.testCache1.cacheattributes.MaxMemoryIdleTime=3600 24 | jcs.region.testCache1.cacheattributes.ShrinkerInterval=60 25 | jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=500 26 | jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes 27 | jcs.region.testCache1.elementattributes.IsEternal=false 28 | 29 | # AVAILABLE AUXILIARY CACHES 30 | jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory 31 | jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes 32 | jcs.auxiliary.DC.attributes.DiskPath=${user.dir}/jcs_swap 33 | jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000 34 | jcs.auxiliary.DC.attributes.MaxKeySize=1000000 35 | jcs.auxiliary.DC.attributes.MaxRecycleBinSize=5000 36 | jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=300000 37 | jcs.auxiliary.DC.attributes.ShutdownSpoolTimeLimit=60 38 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/datastructures/VoiceIntervalPitchList.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.datastructures; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 5 | import com.modulo7.musicstatmodels.musictheorymodels.Interval; 6 | import com.modulo7.musicstatmodels.musictheorymodels.IntervalQuantity; 7 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 8 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by asanyal on 9/8/15. 15 | * 16 | * A data structure that contains the pitch intervals 17 | */ 18 | public class VoiceIntervalPitchList { 19 | 20 | // Pitches on the voices in sequence 21 | private List pitcheIntervalsInSequenceOfVoice = new ArrayList<>(); 22 | 23 | /** 24 | * Computes the voice pitches in sequence 25 | * @param voice 26 | */ 27 | public void computeVoicePitchSet(final Voice voice) throws Modulo7WrongNoteType, Modulo7BadIntervalException { 28 | 29 | final List voiceInstants = voice.getVoiceSequence(); 30 | 31 | for (int i = 0; i < voiceInstants.size() - 1; i++) { 32 | final VoiceInstant currInstant = voice.getVoiceInstantAtPostion(i); 33 | final VoiceInstant nextInstant = voice.getVoiceInstantAtPostion(i + 1); 34 | 35 | final IntervalQuantity interval = Interval.getInterval(currInstant, nextInstant).getIntervalQuantity(); 36 | pitcheIntervalsInSequenceOfVoice.add(interval); 37 | } 38 | } 39 | 40 | /** 41 | * Getter for pitches in sequence of voice 42 | * @return 43 | */ 44 | private List getPitchIntervalsInSequenceOfVoice() { 45 | return pitcheIntervalsInSequenceOfVoice; 46 | } 47 | 48 | /** 49 | * Length of the voice pitch sequence 50 | * @return 51 | */ 52 | public int length() { 53 | return pitcheIntervalsInSequenceOfVoice.size(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/musicmatch/BagOfWordsDataElement.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.musicmatch; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by asanyal on 11/3/15. 10 | * 11 | * Encoding for the music match dataset 12 | */ 13 | public class BagOfWordsDataElement implements Serializable { 14 | 15 | // The track ID 16 | private String trackID; 17 | 18 | // Music match track ID 19 | private String mxmTrackID; 20 | 21 | // Top words and their counts 22 | private Map topWordsCount = new HashMap<>(); 23 | 24 | // Words to count map 25 | private Map wordToCountMap = new HashMap<>(); 26 | 27 | /** 28 | * Construct music match data element from the test or train file 29 | * @param dataElem 30 | * @param topWords 31 | */ 32 | public BagOfWordsDataElement(final String dataElem, final List topWords) { 33 | String[] elements = dataElem.split(","); 34 | trackID = elements[0]; 35 | mxmTrackID = elements[1]; 36 | for (int i = 2; i < elements.length; i++) { 37 | String count = elements[i]; 38 | String[] elementsOfCount = count.split(":"); 39 | 40 | final Integer index = Integer.parseInt(elementsOfCount[0]); 41 | final Integer countOfWord = Integer.parseInt(elementsOfCount[1]); 42 | 43 | topWordsCount.put(index, countOfWord); 44 | wordToCountMap.put(topWords.get(index - 1), countOfWord); 45 | } 46 | } 47 | 48 | /** 49 | * Getter for track ID 50 | * @return 51 | */ 52 | public String getTrackID() { 53 | return trackID; 54 | } 55 | 56 | /** 57 | * Getter for the top word counts for the music match dataset 58 | * @return 59 | */ 60 | public Map getTopWordsCount() { 61 | return topWordsCount; 62 | } 63 | 64 | /** 65 | * Gets the word to counts map 66 | * @return 67 | */ 68 | public Map getWordToCountsMap() { 69 | return wordToCountMap; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/genreestimation/NaiveGenreEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.genreestimation; 2 | 3 | import com.modulo7.pureresearch.lastfm.SongBagLyricsGenreMap; 4 | import com.modulo7.pureresearch.metadataestimation.tagestimation.TagEstimation; 5 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 6 | 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by asanyal on 12/22/15. 14 | */ 15 | public class NaiveGenreEstimation extends GenreEstimation { 16 | 17 | // Threshhold 18 | private double threshHold; 19 | 20 | /** 21 | * Tag estimator default constructor 22 | * 23 | * @param testSet 24 | * @param trainSet 25 | */ 26 | public NaiveGenreEstimation(Set testSet, Set trainSet, final double threshHold) { 27 | super(testSet, trainSet); 28 | this.threshHold = threshHold; 29 | } 30 | 31 | @Override 32 | public Map> getEstimatedGenres() { 33 | 34 | // Init an estimated tags return object 35 | final Map> estimatedTags = new HashMap<>(); 36 | 37 | for (final SongBagLyricsGenreMap dataElem : testSet) { 38 | 39 | final BagOfWordsDataElement testBOG = dataElem.getBagOfWords(); 40 | 41 | final Set unionOfGenres = new HashSet<>(); 42 | 43 | for (final SongBagLyricsGenreMap trainElem : trainSet) { 44 | final BagOfWordsDataElement trainBOG = trainElem.getBagOfWords(); 45 | double simVal = TagEstimation.simVal(testBOG, trainBOG, SIM_CHOICE); 46 | final Set trainGenres = trainElem.getLabels().getGenreList(); 47 | allSeenGenres.addAll(trainGenres); 48 | if (simVal >= threshHold) { 49 | unionOfGenres.addAll(trainGenres); 50 | } 51 | } 52 | 53 | estimatedTags.put(dataElem, unionOfGenres); 54 | } 55 | 56 | return estimatedTags; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/engine/processing/PlaybackEngine.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.engine.processing; 2 | 3 | import com.modulo7.common.exceptions.Modulo7DataBaseNotSerializedException; 4 | import com.modulo7.common.utils.MusicSources; 5 | import com.modulo7.engine.storage.DatabaseEngine; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import com.modulo7.playback.*; 8 | 9 | /** 10 | * Created by asanyal on 10/24/15. 11 | * 12 | * An engine class to play back songs, which allows modulo7 to handle 13 | * arbitrary music sources and play them back, this is necessary as the user 14 | */ 15 | public class PlaybackEngine { 16 | 17 | // A handle to the database engine, fast lookup on source and location of song 18 | private DatabaseEngine engine; 19 | 20 | /** 21 | * Constructor for the playback engine 22 | * @param engine 23 | */ 24 | public PlaybackEngine(final DatabaseEngine engine) { 25 | this.engine = engine; 26 | } 27 | 28 | /** 29 | * Play a given song 30 | * 31 | * @param location 32 | * @throws Modulo7DataBaseNotSerializedException 33 | */ 34 | public void playSong(final String location) throws Modulo7DataBaseNotSerializedException { 35 | 36 | final Song song = engine.getSongGivenLocation(location); 37 | if (song != null) { 38 | if (song.getSource().equals(MusicSources.MIDI)) { 39 | AbstractPlayBack playBack = new MidiPlayBack(location); 40 | playBack.play(); 41 | } else if (song.getSource().equals(MusicSources.MP3)) { 42 | AbstractPlayBack playBack = new MP3PlayBack(location); 43 | playBack.play(); 44 | } else if (song.getSource().equals(MusicSources.MUSIC_XML_FILE)) { 45 | AbstractPlayBack playBack = new MusicXMLPlayback(location); 46 | playBack.play(); 47 | } else if (song.getSource().equals(MusicSources.SHEET_MUSIC)) { 48 | AbstractPlayBack playBack = new SheetMusicPlayBack(location); 49 | playBack.play(); 50 | } else { 51 | System.out.println("File format not supported for playback"); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/WeightedTonalHistogramSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.common.exceptions.Modulo7VectorSizeMismatchException; 4 | import com.modulo7.common.interfaces.AbstractSongSimilarity; 5 | import com.modulo7.common.interfaces.AbstractSongVector; 6 | import com.modulo7.common.utils.Modulo7Globals; 7 | import com.modulo7.common.utils.Modulo7Utils; 8 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 9 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalDurationHistogramData; 10 | import com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors.TonalDurationHistogram; 11 | import org.apache.log4j.Logger; 12 | 13 | /** 14 | * Created by asanyal on 10/11/15. 15 | * 16 | * Similar to the tonal histogram similarity measure, but weighted with the durations of intervals 17 | */ 18 | public class WeightedTonalHistogramSimilarity implements AbstractSongSimilarity { 19 | 20 | private static Logger logger = Logger.getLogger(WeightedTonalHistogramSimilarity.class); 21 | 22 | @Override 23 | public double getSimilarity(Song first, Song second) { 24 | AbstractSongVector tonalHistogram = new TonalDurationHistogram(); 25 | tonalHistogram.computeVectorRepresentation(first); 26 | TonalDurationHistogramData internalVectorOne = tonalHistogram.getInternalRepresentation(); 27 | 28 | AbstractSongVector tonalHistogramSecond = new TonalDurationHistogram(); 29 | tonalHistogramSecond.computeVectorRepresentation(second); 30 | TonalDurationHistogramData internalVectorTwo = tonalHistogramSecond.getInternalRepresentation(); 31 | 32 | try { 33 | return Modulo7Utils.cosineSimilarity(internalVectorOne.getArrayRepresentation(), 34 | internalVectorTwo.getArrayRepresentation()); 35 | } catch (Modulo7VectorSizeMismatchException e) { 36 | logger.error(e.getMessage()); 37 | } 38 | 39 | // If things fail return an unknown value, unlikely it will reach this code path 40 | return Modulo7Globals.UNKNOWN; 41 | } 42 | } -------------------------------------------------------------------------------- /doc/algebra_description: -------------------------------------------------------------------------------- 1 | YOU CAN THINK OF THIS FILE AS THE README OF THE ALGEBRA ASSOCIATED WITH THE QUERYING ENGINE. THIS WOULD ALSO DISCUSS 2 | THE VARIOUS STATISTIC OPERATIONS THAT COULD BE ACQUIRED FOR THE MODULO7 REPRESENTATION. 3 | 4 | CERTAIN BASIC STATISTICS THAT COULD BE USED :- 5 | 6 | 1. MAX MELODIC REPEATING FACTOR - THE RATIO OF THE LONGEST REPEATING PHRASE TO THE TOTAL LENGTH OF THE SONG. 7 | 2. HARMONIC COMPLEXITY - THE LONGEST CHORD SEQUENCE IN THE SONG. 8 | 3. MELODIC ARCH/CONTOUR - GROSS CONTOUR OR STEINBECK CONTOUR OF THE MELODIC ARCH OF A SONG 9 | 10 | OPERATIONS TO BE SUPPORTED :- 11 | 12 | SELECT - SIMILAR TO A SQL SELECT BUT SELECTS A TYPE OF SOURCE, INPUT ALLOWED WOULD BE : MIDI, PNGSHEET, MUSICXML, MP3 13 | PROJECT - DRILL DOWN TO A PARTICULAR VOICE SUPPORTING A CRITERIA OR A STATISTIC 14 | WHERE - ASSERT BEGINNING OF A BLOCK OF ALGEBRA (BOOLEAN MIX OF STAT AND CRITERIA) 15 | AVG(STAT) - AVERAGED STATISTIC OVER ALL VOICES IN THE SONG - RETURNS EITHER A DOUBLE OR A VECTOR OF DOUBLE 16 | MAX(STAT) - MAXIMUM OVER ALL THE VOICES IN THE SONG - RETURNS EITHER A DOUBLE OR A VECTOR OF DOUBLE 17 | MIN(STAT) - MINIMUM OVER ALL THE VOICES IN THE SONG - RETURNS EITHER A DOUBLE OR A VECTOR OF DOUBLE 18 | COUNT(CRITERIA) - RETURNS THE NUMBER OF SONGS THAT SATISFY A CRITERIA 19 | 20 | STAT :- 21 | 22 | STATISTIC COMPUTATION : A PARTICULAR FEATURE AND/OR STATISTIC THAT IS ACQUIRED FROM THE SONG. 23 | INPUT TO A STAT = SONG OR LIST OF SONGS 24 | OUTPUT OF A STAT = A DOUBLE OR A LIST OF DOUBLE 25 | 26 | CRITERIA :- 27 | 28 | CRITERIA SATISFIED BY A SONG : A PARTICULAR MUSIC THEORETIC CRITERIA IF IT IS SATISFIED BY A SONG 29 | INPUT TO A CRITERIA = SONG OR LIST OF SONGS 30 | OUTPUT OF A CRITERIA = BOOLEAN VALUE 31 | 32 | ALGEBRAIC OPERATIONS 33 | 34 | && / AND - SUPPORTS CONCATENATION OF STATS AND/OR CRITERION AND ASSERTS ALL OF THE INPUT MUST BE TRUE FOR OVERALL BLOCK TO BE TRUE 35 | || / OR - SUPPORTS CONCATENATION OF STATS AND/OR CRITERION AND ASSERTS ALL OF THESE MUST BE TRUE FOR OVERALL BLOCK TO BE TRUE 36 | ! / NOT - SUPPORTS THE NOT OPERATION ON A BOOLEAN RETURN, IDEALLY SUITED TO BE USED WITH CRITERIA 37 | > - GREATER THAN, SUPPORTED FOR STAT, NOT DEFINED FOR VECTOR RETURNS 38 | < - LESS THAN, SUPPORTED FOR STAT, NOT DEFINED FOR VECTOR RETURNS 39 | * - DOT PRODUCT, OF TWO VECTORS OR SCALARS 40 | 41 | SOME EXAMPLE QUERIES :- 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/contour/voicecontour/GrossContour.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.common.interfaces.AbstractContour; 5 | import com.modulo7.common.interfaces.AbstractStringContour; 6 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 7 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 8 | 9 | /** 10 | * Created by asanyal on 9/18/15. 11 | * 12 | * The gross contour just takes into account upward and downward motion of notes, 13 | * it does not take into account the magnnitude of the motion 14 | * 15 | * Gross contour similarity can be used to understand similar and parallel motion 16 | * as well anti parallel motion but can distinguish between similar and parallel 17 | * motion in melodies 18 | */ 19 | public class GrossContour implements AbstractStringContour { 20 | 21 | @Override 22 | public String getContourRepresentaionOfVoice(final Voice voice) { 23 | 24 | StringBuilder countourRep = new StringBuilder(); 25 | 26 | int voiceInstantIndex = 0; 27 | final int maxVoiceInstantIndex = voice.getNumVoiceInstantsOfVoice(); 28 | 29 | for (final VoiceInstant voiceInstant : voice.getVoiceSequence()) { 30 | 31 | if (voiceInstantIndex < maxVoiceInstantIndex - 1) { 32 | final VoiceInstant nPlusOne = voice.getVoiceInstantAtPostion(voiceInstantIndex + 1); 33 | 34 | try { 35 | final boolean isBelow = VoiceInstant.isLowerPitch(nPlusOne, voiceInstant); 36 | final boolean isAbove = VoiceInstant.isHigherPitch(nPlusOne, voiceInstant); 37 | 38 | if (isBelow) { 39 | countourRep.append("D "); 40 | } else if (isAbove) { 41 | countourRep.append("U "); 42 | } else { 43 | countourRep.append("S "); 44 | } 45 | } catch (Modulo7WrongNoteType e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | voiceInstantIndex++; 50 | } 51 | 52 | return countourRep.toString().trim(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/contour/voicecontour/MullensiefenContour.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.common.interfaces.AbstractContour; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 7 | import org.apache.log4j.Logger; 8 | 9 | import java.util.HashSet; 10 | import java.util.LinkedHashMap; 11 | import java.util.Set; 12 | 13 | /** 14 | * Created by asanyal on 9/8/15. 15 | * 16 | * MullensiefenContour as described in SIMILE technical manual 17 | * 18 | * Removes notes that are in between notes that identical in pitch 19 | * 20 | */ 21 | public class MullensiefenContour implements AbstractContour { 22 | 23 | // Logger for mullensiefen contour 24 | private Logger logger = Logger.getLogger(MullensiefenContour.class); 25 | 26 | public MullensiefenContour() { 27 | 28 | } 29 | 30 | @Override 31 | public LinkedHashMap getContourRepresentaionOfVoice(final Voice voice) { 32 | 33 | AbstractContour naturalContour = new NaturalContour(); 34 | LinkedHashMap naturalExtemumNotes = naturalContour.getContourRepresentaionOfVoice(voice); 35 | 36 | Set changingNoteIndices = new HashSet<>(); 37 | 38 | final int maxVoiceInstantIndex = voice.getNumVoiceInstantsOfVoice(); 39 | 40 | for (int voiceInstantIndex = 1 ; voiceInstantIndex < maxVoiceInstantIndex - 1; voiceInstantIndex++) { 41 | final VoiceInstant nMinusOne = voice.getVoiceInstantAtPostion(voiceInstantIndex - 1); 42 | final VoiceInstant nPlusOne = voice.getVoiceInstantAtPostion(voiceInstantIndex + 1); 43 | 44 | try { 45 | if (VoiceInstant.isEqualPitch(nMinusOne, nPlusOne)) { 46 | changingNoteIndices.add(voiceInstantIndex); 47 | } 48 | } catch (Modulo7WrongNoteType e) { 49 | logger.error(e.getMessage()); 50 | } 51 | } 52 | 53 | changingNoteIndices.forEach(naturalExtemumNotes::remove); 54 | 55 | return naturalExtemumNotes; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/tagestimation/NaiveTagEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.tagestimation; 2 | 3 | import com.modulo7.pureresearch.lastfm.SongBagLyricsAndMetadata; 4 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 5 | 6 | import java.io.IOException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * Created by asanyal on 12/11/15. 13 | * 14 | * Implementation of the naive tag estimation algorithm defined in Modulo7 15 | */ 16 | public class NaiveTagEstimation extends TagEstimation { 17 | 18 | /** 19 | * Default deserialization constructor for lyrics map to tags 20 | * 21 | * @param lyricsTagMapSerialized 22 | */ 23 | public NaiveTagEstimation(final String lyricsTagMapSerialized) throws IOException, ClassNotFoundException { 24 | super(lyricsTagMapSerialized); 25 | } 26 | 27 | 28 | /** 29 | * Constructor with the test and train sets already defined 30 | * @param testSet 31 | * @param trainSet 32 | */ 33 | public NaiveTagEstimation(final Set testSet, final Set trainSet) { 34 | super(testSet, trainSet); 35 | } 36 | 37 | @Override 38 | public Map> getEstimatedTags() { 39 | 40 | // Init an estimated tags return object 41 | final Map> estimatedTags = new HashMap<>(); 42 | 43 | for (final SongBagLyricsAndMetadata dataElem : testSet) { 44 | final BagOfWordsDataElement testBOG = dataElem.getBagOfWords(); 45 | 46 | final Map unionOfTags = new HashMap<>(); 47 | 48 | for (final SongBagLyricsAndMetadata trainElem : trainSet) { 49 | final BagOfWordsDataElement trainBOG = trainElem.getBagOfWords(); 50 | double simVal = simVal(testBOG, trainBOG, SIM_CHOICE); 51 | if (simVal > THRESHHOLD) { 52 | final Map trainTags = trainElem.getTags(); 53 | unionOfTags.putAll(trainTags); 54 | } 55 | } 56 | 57 | estimatedTags.put(dataElem, unionOfTags); 58 | } 59 | 60 | return estimatedTags; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/MostFrequentScaleDegree.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 5 | import com.modulo7.common.interfaces.AbstractStatistic; 6 | import com.modulo7.musicstatmodels.musictheorymodels.Interval; 7 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 8 | import com.modulo7.musicstatmodels.representation.metadata.KeySignature; 9 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 10 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 11 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 12 | import org.apache.log4j.Logger; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * Created by asanyal on 1/6/16. 19 | * 20 | * A statistic which captures the most frequent scale degree 21 | * Its a useful statistic as it can lead to some interesting observations 22 | * (for instance blues music has a prevalence of the worry note, absent in 23 | * other music) 24 | * 25 | * TODO : Finish this implementation 26 | */ 27 | public class MostFrequentScaleDegree implements AbstractStatistic { 28 | 29 | // Logger instance 30 | private static final Logger logger = Logger.getLogger(MostFrequentScaleDegree.class); 31 | 32 | // Scale degree frequency 33 | private Map scaleDegreeFrequency = new HashMap<>(); 34 | 35 | @Override 36 | public Double getStatistic(final Song song) { 37 | final KeySignature signature = song.getMetadata().getKeySignature(); 38 | final String key = signature.getKey(); 39 | 40 | for (final Voice voice : song.getVoices()) { 41 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 42 | for (final Note note : instant.getAllNotesofInstant()) { 43 | final String noteVal = note.getNoteValue(); 44 | try { 45 | final Interval scaleDegree = Note.getInterval(noteVal, key); 46 | } catch (Modulo7BadNoteException | Modulo7BadIntervalException e) { 47 | logger.error(e.getMessage()); 48 | } 49 | } 50 | } 51 | } 52 | 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/testdata/lyrics/barbie_girl: -------------------------------------------------------------------------------- 1 | Hi Barbie 2 | Hi Ken! 3 | Do you wanna go for a ride? 4 | Sure Ken! 5 | Jump in... 6 | 7 | I'm a Barbie girl, in the Barbie world 8 | Life in plastic, it's fantastic! 9 | You can brush my hair, undress me everywhere 10 | Imagination, life is your creation 11 | Come on Barbie, let's go party! 12 | 13 | I'm a Barbie girl, in the Barbie world 14 | Life in plastic, it's fantastic! 15 | You can brush my hair, undress me everywhere 16 | Imagination, life is your creation 17 | 18 | I'm a blond bimbo girl, in a fantasy world 19 | Dress me up, make it tight, I'm your dolly 20 | You're my doll, rock'n'roll, feel the glamour in pink, 21 | Kiss me here, touch me there, hanky panky... 22 | You can touch, you can play, if you say: "I'm always yours" 23 | 24 | (uu-oooh-u) [2x] 25 | 26 | I'm a Barbie girl, in the Barbie world 27 | Life in plastic, it's fantastic! 28 | You can brush my hair, undress me everywhere 29 | Imagination, life is your creation 30 | 31 | Come on Barbie, let's go party! 32 | (Ah-ah-ah-yeah) 33 | Come on Barbie, let's go party! 34 | (uu-oooh-u) [2x] 35 | Come on Barbie, let's go party! 36 | (Ah-ah-ah-yeah) 37 | Come on Barbie, let's go party! 38 | (uu-oooh-u) [2x] 39 | 40 | Make me walk, make me talk, do whatever you please 41 | I can act like a star, I can beg on my knees 42 | Come jump in, bimbo friend, let us do it again, 43 | Hit the town, fool around, let's go party 44 | You can touch, you can play, if you say: "I'm always yours" 45 | You can touch, you can play, if you say: "I'm always yours" 46 | 47 | Come on Barbie, let's go party! 48 | (Ah-ah-ah-yeah) 49 | Come on Barbie, let's go party! 50 | (uu-oooh-u) [2x] 51 | Come on Barbie, let's go party! 52 | (Ah-ah-ah-yeah) 53 | Come on Barbie, let's go party! 54 | (uu-oooh-u) [2x] 55 | 56 | I'm a Barbie girl, in the Barbie world 57 | Life in plastic, it's fantastic! 58 | You can brush my hair, undress me everywhere 59 | Imagination, life is your creation 60 | 61 | I'm a Barbie girl, in the Barbie world 62 | Life in plastic, it's fantastic! 63 | You can brush my hair, undress me everywhere 64 | Imagination, life is your creation 65 | 66 | Come on Barbie, let's go party! 67 | (Ah-ah-ah-yeah) 68 | Come on Barbie, let's go party! 69 | (uu-oooh-u) [2x] 70 | Come on Barbie, let's go party! 71 | (Ah-ah-ah-yeah) 72 | Come on Barbie, let's go party! 73 | (uu-oooh-u) [2x] 74 | 75 | Oh, I'm having so much fun! 76 | Well Barbie, we're just getting started 77 | Oh, I love you Ken! 78 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/UkkonnenSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.common.utils.Modulo7Utils; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by asanyal on 10/13/15. 12 | * 13 | * Ukkonnen measure as described in SIMILIE technical documentation 14 | */ 15 | public class UkkonnenSimilarity implements AbstractVoiceSimilarity { 16 | 17 | // Number of grams, default to 3 18 | private int N = 3; 19 | 20 | /** 21 | * Ukkonnen similarity measure constructor with custom number of grams 22 | * @param n 23 | */ 24 | public UkkonnenSimilarity(final int n) { 25 | N = n; 26 | } 27 | 28 | /** 29 | * Ukkonnen default constructor 30 | */ 31 | public UkkonnenSimilarity() { 32 | } 33 | 34 | @Override 35 | public double getSimilarity(final Voice first, final Voice second) { 36 | 37 | // Compute the distinct N grams in the first voice 38 | final Map distinctTrigramsInOne = new HashMap<>(); 39 | 40 | // Compute the distinct N grams in the second voice 41 | final Map distinctTrigramsInTwo = new HashMap<>(); 42 | 43 | final String firstSetDoc = first.getDocumentRepresentation(); 44 | final String secondSetDoc = second.getDocumentRepresentation(); 45 | 46 | String[] firstSplit = firstSetDoc.split(" "); 47 | String[] secondSplit = secondSetDoc.split(" "); 48 | 49 | for (int i = 0; i < firstSplit.length - N; i++) { 50 | String ngram = ""; 51 | for (int k = i; k < i + N; k++) 52 | ngram += firstSplit[k]; 53 | Modulo7Utils.addToCount(ngram, distinctTrigramsInOne); 54 | } 55 | 56 | for (int i = 0; i < secondSplit.length - N; i++) { 57 | String ngram = ""; 58 | for (int k = i; k < i + N; k++) 59 | ngram += secondSplit[k]; 60 | Modulo7Utils.addToCount(ngram, distinctTrigramsInTwo); 61 | } 62 | 63 | return 1 - (double) (Math.abs(Modulo7Utils.sumOverNGramFreqs(distinctTrigramsInOne) - Modulo7Utils.sumOverNGramFreqs(distinctTrigramsInTwo))) 64 | / (firstSplit.length + secondSplit.length - 2*(N - 1)); 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/songsimilarity/TonalHistogramSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.songsimilarity; 2 | 3 | import com.modulo7.common.exceptions.Modulo7VectorSizeMismatchException; 4 | import com.modulo7.common.interfaces.AbstractSongSimilarity; 5 | import com.modulo7.common.utils.Modulo7Globals; 6 | import com.modulo7.common.utils.Modulo7Utils; 7 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 8 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalHistogramData; 9 | import com.modulo7.common.interfaces.AbstractSongVector; 10 | import com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors.TonalHistogram; 11 | import org.apache.log4j.Logger; 12 | 13 | /** 14 | * Created by asanyal on 8/30/15. 15 | * 16 | * Tonal histogram similarity measure is based on the fact that the tonal histogram 17 | * can act as an vectorized representation of the song. As such the cosine similarity 18 | * or any other such measure can also be used 19 | */ 20 | public class TonalHistogramSimilarity implements AbstractSongSimilarity { 21 | 22 | // Logger for tonal histogram similarity 23 | private static final Logger logger = Logger.getLogger(TonalHistogramSimilarity.class); 24 | 25 | /** 26 | * Gets similarity based on tonal histograms 27 | * @param first 28 | * @param second 29 | * @return 30 | */ 31 | @Override 32 | public double getSimilarity(final Song first, final Song second) { 33 | AbstractSongVector tonalHistogram = new TonalHistogram(); 34 | tonalHistogram.computeVectorRepresentation(first); 35 | TonalHistogramData internalVectorOne = tonalHistogram.getInternalRepresentation(); 36 | 37 | AbstractSongVector tonalHistogramSecond = new TonalHistogram(); 38 | tonalHistogramSecond.computeVectorRepresentation(second); 39 | TonalHistogramData internalVectorTwo = tonalHistogramSecond.getInternalRepresentation(); 40 | 41 | try { 42 | return Modulo7Utils.cosineSimilarity(internalVectorOne.getArrayRepresentation(), 43 | internalVectorTwo.getArrayRepresentation()); 44 | } catch (Modulo7VectorSizeMismatchException e) { 45 | logger.error(e.getMessage()); 46 | } 47 | 48 | // If things fail return an unknown value, unlikely it will reach this code path 49 | return Modulo7Globals.UNKNOWN; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/CountDistanceSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * Created by asanyal on 11/7/15. 11 | * 12 | * Based on the similie technical manual, the count distance similarity is 13 | * based on the count(number) of common trigrams, rather than the actual frequecies 14 | */ 15 | public class CountDistanceSimilarity implements AbstractVoiceSimilarity { 16 | 17 | // Number of grams, default to 3 18 | private int N = 3; 19 | 20 | /** 21 | * CountDistanceSimilarity measure constructor with custom number of grams 22 | * @param n 23 | */ 24 | public CountDistanceSimilarity(final int n) { 25 | N = n; 26 | } 27 | 28 | /** 29 | * CountDistanceSimilarity default constructor 30 | */ 31 | public CountDistanceSimilarity() { 32 | } 33 | 34 | @Override 35 | public double getSimilarity(final Voice first, final Voice second) { 36 | 37 | // Compute the distinct N grams in the first voice 38 | final Set distinctTrigramsInOne = new HashSet<>(); 39 | 40 | // Compute the distinct N grams in the second voice 41 | final Set distinctTrigramsInTwo = new HashSet<>(); 42 | 43 | final String firstSetDoc = first.getDocumentRepresentation(); 44 | final String secondSetDoc = second.getDocumentRepresentation(); 45 | 46 | String[] firstSplit = firstSetDoc.split(" "); 47 | String[] secondSplit = secondSetDoc.split(" "); 48 | 49 | for (int i = 0; i < firstSplit.length - N; i++) { 50 | String ngram = ""; 51 | for (int k = i; k < i + N; k++) 52 | ngram += firstSplit[k]; 53 | distinctTrigramsInOne.add(ngram); 54 | } 55 | 56 | for (int i = 0; i < secondSplit.length - N; i++) { 57 | String ngram = ""; 58 | for (int k = i; k < i + N; k++) 59 | ngram += secondSplit[k]; 60 | distinctTrigramsInTwo.add(ngram); 61 | } 62 | 63 | // Intersection of both sets 64 | distinctTrigramsInOne.retainAll(distinctTrigramsInTwo); 65 | 66 | return (double) distinctTrigramsInOne.size() / Math.max(firstSplit.length, secondSplit.length); 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/preprocessing/TonalityAlignment.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.preprocessing; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 5 | import com.modulo7.common.utils.FrequencyNoteMap; 6 | import com.modulo7.musicstatmodels.musictheorymodels.Interval; 7 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 8 | import com.modulo7.musicstatmodels.representation.metadata.KeySignature; 9 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 10 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 11 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 12 | import org.apache.commons.lang3.SerializationUtils; 13 | 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | import java.util.stream.Collectors; 17 | 18 | /** 19 | * Created by asanyal on 9/17/15. 20 | * 21 | * Bring a song to a given key as a proprocessing step 22 | * This is necessary for execution of certain similarity measures 23 | */ 24 | public class TonalityAlignment { 25 | 26 | private static FrequencyNoteMap noteMap = FrequencyNoteMap.getInstance(); 27 | 28 | /** 29 | * Method which aligns songs to a particular key signature so every note is shifted 30 | * by a set interval 31 | * 32 | * @param song 33 | * @param desiredKeySignature 34 | * @throws Modulo7BadIntervalException 35 | * @throws Modulo7BadNoteException 36 | */ 37 | public static Song alignSong(final Song song, KeySignature desiredKeySignature) throws Modulo7BadIntervalException, 38 | Modulo7BadNoteException { 39 | final KeySignature currentKeySignature = song.getMetadata().getKeySignature(); 40 | final Interval interval = KeySignature.getIntervalicDistance(currentKeySignature, desiredKeySignature); 41 | 42 | Song newSong = SerializationUtils.clone(song); 43 | 44 | newSong.getMetadata().setKeySignature(desiredKeySignature); 45 | 46 | for (final Voice voice : newSong.getVoices()) { 47 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 48 | final Set newNoteSet = 49 | instant.getAllNotesofInstant().parallelStream().map(note -> noteMap.getNoteGivenBaseAndInterval(note, interval)).collect(Collectors.toSet()); 50 | instant.reassignNotes(new HashSet<>(newNoteSet)); 51 | } 52 | } 53 | 54 | return newSong; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/tagestimation/MaxFrequencyTagEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.tagestimation; 2 | 3 | import com.modulo7.common.utils.Modulo7Utils; 4 | import com.modulo7.pureresearch.lastfm.SongBagLyricsAndMetadata; 5 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 6 | 7 | import java.io.IOException; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by asanyal on 12/11/15. 14 | * 15 | * Tags estimated based on highest frequency of tags 16 | */ 17 | public class MaxFrequencyTagEstimation extends TagEstimation { 18 | /** 19 | * Default deserialization constructor for lyrics map to tags 20 | * 21 | * @param lyricsTagMapSerialized 22 | */ 23 | public MaxFrequencyTagEstimation(final String lyricsTagMapSerialized) throws IOException, ClassNotFoundException { 24 | super(lyricsTagMapSerialized); 25 | } 26 | 27 | /** 28 | * Constructor with the test and train sets already defined 29 | * @param testSet 30 | * @param trainSet 31 | */ 32 | public MaxFrequencyTagEstimation(final Set testSet, final Set trainSet) { 33 | super(testSet, trainSet); 34 | } 35 | 36 | @Override 37 | public Map> getEstimatedTags() { 38 | 39 | // Init an estimated tags return object 40 | final Map> estimatedTags = new HashMap<>(); 41 | 42 | for (final SongBagLyricsAndMetadata dataElem : testSet) { 43 | final BagOfWordsDataElement bogTest = dataElem.getBagOfWords(); 44 | 45 | final Map tagFrequency = new HashMap<>(); 46 | for (final SongBagLyricsAndMetadata trainElem : trainSet) { 47 | final Map trainTags = trainElem.getTags(); 48 | final BagOfWordsDataElement bogTrain = trainElem.getBagOfWords(); 49 | double simVal = simVal(bogTest, bogTrain, SIM_CHOICE); 50 | if (simVal >= THRESHHOLD) { 51 | for (Map.Entry tagEntry : trainTags.entrySet()) { 52 | Modulo7Utils.addToCount(tagEntry.getKey(), trainTags, 1); 53 | } 54 | } 55 | } 56 | 57 | estimatedTags.put(dataElem, tagFrequency); 58 | } 59 | 60 | return estimatedTags; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/PowerIndex.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongVector; 4 | import com.modulo7.common.interfaces.AbstractStatistic; 5 | import com.modulo7.musicstatmodels.musictheorymodels.IntervalQuantity; 6 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 7 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalHistogramData; 8 | import com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors.TonalHistogram; 9 | 10 | /** 11 | * Created by asanyal on 8/29/15. 12 | * 13 | * The power index is a basic statistic which includes the number of perfect intervals 14 | * in a given song / total number of intervals or notes in the song (a mathematically precise 15 | * way of computing the number of 16 | * 17 | * The power index might be weighted in order to get a particular interval some more precedence. 18 | * These weights are based on user preference and Modulo7 does not claim to understand the meaning 19 | * or significance of these weights TODO : Implement this weighted version and figure out what it 20 | * would mean 21 | * 22 | * Power index is a rudimentary quantification of the neutrality/power associated with the song. 23 | * Rock songs generally tend to have higher power indices 24 | */ 25 | public class PowerIndex implements AbstractStatistic { 26 | 27 | /** 28 | * Default constructor of power index 29 | */ 30 | public PowerIndex() { 31 | 32 | } 33 | 34 | /** 35 | * Gets the perfect intervals vs total intervals ratio 36 | * @param song 37 | * @return 38 | */ 39 | @Override 40 | public Double getStatistic(final Song song) { 41 | AbstractSongVector tonalHistogram = new TonalHistogram(); 42 | tonalHistogram.computeVectorRepresentation(song); 43 | TonalHistogramData histogramData = tonalHistogram.getInternalRepresentation(); 44 | 45 | final int totalSum = histogramData.getHistogramTotalSum(); 46 | 47 | int perfectSum = 0; 48 | 49 | // Add perfect intervals to perfect sum 50 | perfectSum += histogramData.getCountForInterval(IntervalQuantity.PERFECT_UNISON); 51 | perfectSum += histogramData.getCountForInterval(IntervalQuantity.PERFECT_FIFTH); 52 | perfectSum += histogramData.getCountForInterval(IntervalQuantity.PERFECT_OCTAVE); 53 | perfectSum += histogramData.getCountForInterval(IntervalQuantity.PERFECT_FOURTH); 54 | 55 | return (double)(perfectSum) / totalSum; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/songvectors/PitchDurationHistogram.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors; 2 | 3 | import com.modulo7.common.interfaces.AbstractSongVector; 4 | import com.modulo7.musicstatmodels.representation.buildingblocks.ChordQuality; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 7 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 8 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.PitchDurationHistogramData; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by asanyal on 10/2/15. 14 | * 15 | * Vector representation of the pitch duration histogram 16 | */ 17 | public class PitchDurationHistogram implements AbstractSongVector { 18 | 19 | // Internal pitchDurationHistogram representation 20 | private PitchDurationHistogramData pitchDurationHistogram; 21 | 22 | /** 23 | * Default constructor for tonal histogram and the only one present 24 | */ 25 | public PitchDurationHistogram() { 26 | pitchDurationHistogram = new PitchDurationHistogramData(); 27 | } 28 | 29 | @Override 30 | public void computeVectorRepresentation(final Song song) { 31 | for (Voice voice : song.getVoices()) { 32 | List voiceInstants = voice.getVoiceSequence(); 33 | 34 | /** 35 | * Acquire each of the voice instants and if 36 | */ 37 | for (int i = 0; i < voiceInstants.size() - 1; i++) { 38 | VoiceInstant instant = voiceInstants.get(i); 39 | 40 | 41 | String noteValue = ChordQuality.getRootNoteFromChord(instant.getAllNotesofInstant()).getNoteValue(); 42 | addPitchDurationToHistogram(noteValue, instant.getDuration()); 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | public PitchDurationHistogramData getInternalRepresentation() { 49 | return pitchDurationHistogram; 50 | } 51 | 52 | /** 53 | * Helper method to add interval duration to pitchDurationHistogram 54 | * 55 | * @param interval 56 | * @param duration 57 | */ 58 | private synchronized void addPitchDurationToHistogram(final String interval, final double duration) { 59 | Double currCumulativeDuration = pitchDurationHistogram.getData(interval); 60 | pitchDurationHistogram.setData(interval, currCumulativeDuration + duration); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/playback/SheetMusicPlayBack.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.playback; 2 | 3 | import com.modulo7.common.utils.JarRunner; 4 | import com.modulo7.image.AudiverisSheetAnalyzer; 5 | import nu.xom.ParsingException; 6 | import org.apache.commons.io.FileUtils; 7 | import org.apache.commons.io.FilenameUtils; 8 | import org.apache.log4j.Logger; 9 | import org.jfugue.integration.MusicXmlParser_J; 10 | import org.jfugue.pattern.Pattern; 11 | import org.jfugue.player.Player; 12 | import org.staccato.StaccatoParserListener; 13 | 14 | import javax.xml.parsers.ParserConfigurationException; 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.lang.reflect.InvocationTargetException; 18 | 19 | /** 20 | * Created by asanyal on 10/24/15. 21 | * 22 | * Sheet music file playback class 23 | */ 24 | public class SheetMusicPlayBack implements AbstractPlayBack { 25 | 26 | // Sheet music file location 27 | private String sheetFileLocation; 28 | 29 | // Intermediate music xml location 30 | private String intermediateMusicXMLLocation; 31 | 32 | // Logger for sheet music analyzer 33 | private static Logger logger = Logger.getLogger(SheetMusicPlayBack.class); 34 | 35 | /** 36 | * Basic constructor for music xml playback 37 | * @param sheetFileLocation 38 | */ 39 | public SheetMusicPlayBack(final String sheetFileLocation) { 40 | this.sheetFileLocation = sheetFileLocation; 41 | intermediateMusicXMLLocation = FileUtils.getTempDirectoryPath() + 42 | File.separator + FilenameUtils.getBaseName(sheetFileLocation) + ".xml"; 43 | } 44 | 45 | @Override 46 | public void play() { 47 | try { 48 | JarRunner runner = AudiverisSheetAnalyzer.getAudiverisJarRunner(); 49 | runner.run(new String[]{"-batch", "-input", sheetFileLocation, "-export", intermediateMusicXMLLocation}); 50 | MusicXmlParser_J parser = new MusicXmlParser_J(); 51 | StaccatoParserListener listener = new StaccatoParserListener(); 52 | parser.addParserListener(listener); 53 | parser.parse(intermediateMusicXMLLocation); 54 | Player player = new Player(); 55 | final Pattern musicXMLPattern = listener.getPattern(); 56 | player.play(musicXMLPattern); 57 | } catch (IllegalAccessException | InvocationTargetException | ParserConfigurationException | IOException| ParsingException e) { 58 | logger.error(e.getMessage()); 59 | } finally { 60 | FileUtils.deleteQuietly(new File(intermediateMusicXMLLocation)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/bagofwordslyricssim/BOWSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.bagofwordslyricssim; 2 | 3 | import org.apache.commons.math.linear.ArrayRealVector; 4 | import org.apache.commons.math.linear.RealVector; 5 | import org.apache.lucene.search.similarities.Similarity; 6 | 7 | import java.util.HashSet; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * Created by asanyal on 12/12/15. 13 | * 14 | * An abstract bag of word similarity metric, 15 | * all measures as implementation of 16 | */ 17 | public abstract class BOWSimilarity { 18 | 19 | // A given similarity metric derived from lucene similarity measures 20 | protected Similarity similarity; 21 | 22 | // Terms for bag of words for the first set 23 | protected RealVector v1; 24 | 25 | // Terms for bag of words for the second set 26 | protected RealVector v2; 27 | 28 | /** 29 | * Base constructor 30 | * 31 | * @param bog1 32 | * @param bog2 33 | */ 34 | public BOWSimilarity(final Map bog1, final Map bog2) { 35 | 36 | Set terms = new HashSet<>(bog1.keySet()); 37 | Set otherTerms = new HashSet<>(bog2.keySet()); 38 | 39 | terms.addAll(otherTerms); 40 | 41 | v1 = toRealVector(bog1, terms); 42 | v2 = toRealVector(bog2, terms); 43 | } 44 | 45 | /** 46 | * Get the similarity between two elements based on particular 47 | * similarity criteria, implementation dependent on 48 | * @return 49 | */ 50 | public abstract double getSimVal(); 51 | 52 | /** 53 | * Gets the real vector representation of a set of terms 54 | * 55 | * @param terms 56 | * @param map 57 | * @return 58 | */ 59 | private RealVector toRealVector(final Map map, final Set terms) { 60 | 61 | RealVector vector = new ArrayRealVector(terms.size()); 62 | int i = 0; 63 | 64 | for (String term : terms) { 65 | int value = map.containsKey(term) ? map.get(term) : 0; 66 | vector.setEntry(i++, value); 67 | } 68 | 69 | return vector.mapDivide(vector.getL1Norm()); 70 | } 71 | 72 | /** 73 | * Gets vector sum 74 | * @param vector 75 | * @return 76 | */ 77 | double getVectorSum(final RealVector vector) { 78 | 79 | double sum = 0.0; 80 | 81 | for (int i = 0; i < vector.getDimension(); i++) { 82 | sum += vector.getEntry(i); 83 | } 84 | 85 | return sum; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/genericsimilarity/SongContourSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.genericsimilarity; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7BadNoteException; 5 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 6 | import com.modulo7.common.interfaces.AbstractContour; 7 | import com.modulo7.common.interfaces.AbstractSongSimilarity; 8 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 9 | import com.modulo7.common.utils.Modulo7Globals; 10 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 11 | import com.modulo7.musicstatmodels.vectorspacemodels.contour.ContourSongRep; 12 | import org.apache.log4j.Logger; 13 | 14 | /** 15 | * Created by asanyal on 10/2/15. 16 | * 17 | * A similarity measure using natural song contour on arbitrary voice similarity measures 18 | */ 19 | public class SongContourSimilarity 20 | implements AbstractSongSimilarity { 21 | 22 | // Logger for natural song contour similarity measure 23 | private static Logger logger = Logger.getLogger(SongContourSimilarity.class); 24 | 25 | // The internal voice similarity used with the contour similarity 26 | private T internalVoiceSimilarity; 27 | 28 | // The internal contour representation used in the voice similarity 29 | private V internalContourRep; 30 | 31 | /** 32 | * Basic constructor for natural song contour similarity 33 | * @param internalVoiceSimilarity 34 | */ 35 | public SongContourSimilarity(final T internalVoiceSimilarity, final V internalContourRep) { 36 | this.internalVoiceSimilarity = internalVoiceSimilarity; 37 | this.internalContourRep = internalContourRep; 38 | } 39 | 40 | @Override 41 | public double getSimilarity(final Song first, final Song second) { 42 | 43 | ContourSongRep songRep = new ContourSongRep<>(internalContourRep); 44 | 45 | try { 46 | final Song firstContourRepSong = songRep.getContourizedSongRep(first); 47 | final Song secondContourRepSong = songRep.getContourizedSongRep(second); 48 | 49 | GeneralMaximalVoiceSimilarity similarity = new GeneralMaximalVoiceSimilarity<>(internalVoiceSimilarity); 50 | return similarity.getSimilarity(firstContourRepSong, secondContourRepSong); 51 | } catch (Modulo7BadIntervalException | Modulo7WrongNoteType | Modulo7BadNoteException e) { 52 | logger.error(e.getMessage()); 53 | } 54 | 55 | return Modulo7Globals.UNKNOWN; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/statistics/MostFrequentPitch.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.statistics; 2 | 3 | import com.modulo7.common.interfaces.AbstractStatistic; 4 | import com.modulo7.common.utils.FrequencyNoteMap; 5 | import com.modulo7.common.utils.Modulo7Utils; 6 | import com.modulo7.musicstatmodels.representation.buildingblocks.Note; 7 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 8 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 9 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 10 | 11 | import java.util.*; 12 | import java.util.function.Function; 13 | import java.util.function.ToDoubleFunction; 14 | import java.util.function.ToIntFunction; 15 | import java.util.function.ToLongFunction; 16 | 17 | /** 18 | * Created by asanyal on 1/6/16. 19 | * 20 | * Extracts the most frequently occuring pitch in numeric format 21 | * 22 | * The output is an integer which maps to the keyboard location for that note 23 | * Unknowns map to -1 24 | */ 25 | public class MostFrequentPitch implements AbstractStatistic { 26 | 27 | // Map storing notes with their associated counters 28 | private Map noteCounts = new HashMap<>(); 29 | 30 | // A handle to the static note map instant, used for ascertaining position given 31 | private static final FrequencyNoteMap noteMap = FrequencyNoteMap.getInstance(); 32 | 33 | @Override 34 | public Double getStatistic(final Song song) { 35 | for (final Voice voice : song.getVoices()) { 36 | for (final VoiceInstant instant : voice.getVoiceSequence()) { 37 | Set noteSet = instant.getAllNotesofInstant(); 38 | noteSet.forEach(this::addToNoteCount); 39 | } 40 | } 41 | 42 | return noteMap.getPositionGivenNote(Collections.max(noteCounts.entrySet(), new MapFreqComparator()).getKey()) * 1.0; 43 | } 44 | 45 | /** 46 | * Addition to note counter 47 | * @param note 48 | */ 49 | private void addToNoteCount(final Note note) { 50 | final Integer count = noteCounts.get(note); 51 | if (count != null) { 52 | noteCounts.put(note, count + 1); 53 | } else { 54 | noteCounts.put(note, 1); 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * Implements a comparator for max frequency of note occuring in the 61 | */ 62 | class MapFreqComparator implements Comparator> { 63 | 64 | @Override 65 | public int compare(Map.Entry thisNoteEntry, Map.Entry thatNoteEntry) { 66 | return thisNoteEntry.getValue() > thatNoteEntry.getValue()? 1:-1; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/common/utils/HDFSUtils.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.common.utils; 2 | 3 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 4 | import org.apache.avro.Schema; 5 | import org.apache.avro.file.DataFileReader; 6 | import org.apache.avro.file.DataFileWriter; 7 | import org.apache.avro.file.SeekableInput; 8 | import org.apache.avro.io.DatumReader; 9 | import org.apache.avro.io.DatumWriter; 10 | import org.apache.avro.mapred.FsInput; 11 | import org.apache.avro.reflect.ReflectDatumReader; 12 | import org.apache.avro.reflect.ReflectDatumWriter; 13 | import org.apache.hadoop.conf.Configuration; 14 | import org.apache.hadoop.fs.FileSystem; 15 | import org.apache.hadoop.fs.Path; 16 | 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.io.OutputStream; 20 | 21 | /** 22 | * Created by asanyal on 9/30/15. 23 | * 24 | * Utility methods for storing and retrieving objects from HDFS 25 | */ 26 | public class HDFSUtils { 27 | 28 | // Acquire the reflective schema from Modulo7 class 29 | private static final Schema schema = Song.getSongSchema(); 30 | 31 | /** 32 | * Utility method to read from HDFS Store a Modulo7 song object 33 | * 34 | * @param path 35 | * @throws IOException 36 | */ 37 | private Song m7HDFSRead(final String path) throws IOException { 38 | Path hdfsPath = new Path(path); 39 | Configuration config = new Configuration(); 40 | SeekableInput input = new FsInput(hdfsPath, config); 41 | DatumReader reader = new ReflectDatumReader<>(Song.class); 42 | DataFileReader dataFileReader = new DataFileReader<>(input, reader); 43 | 44 | for (Song song : dataFileReader) { 45 | return song; 46 | } 47 | 48 | dataFileReader.close(); // also closes underlying FsInput 49 | 50 | return null; 51 | } 52 | 53 | /** 54 | * Writes a song object to HDFS store 55 | * @param song 56 | * @param dstPath 57 | */ 58 | private void myHDFSWrite(final Song song, final String dstPath) throws IOException { 59 | 60 | Configuration conf = new Configuration(); 61 | FileSystem fs = FileSystem.get(conf); 62 | ReflectDatumWriter reflectDatumWriter = new ReflectDatumWriter<>(Song.class); 63 | DataFileWriter dataFileWriter = new DataFileWriter<>(reflectDatumWriter); 64 | 65 | Path filePath = new Path(dstPath); 66 | OutputStream out = fs.create(filePath); 67 | 68 | DataFileWriter hdfsWriter = dataFileWriter.create(schema, out); 69 | hdfsWriter.append(song); 70 | 71 | hdfsWriter.close(); 72 | out.close(); 73 | dataFileWriter.close(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/similarity/voicesimilarity/SCMNGramSimilarity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.similarity.voicesimilarity; 2 | 3 | import com.modulo7.common.interfaces.AbstractVoiceSimilarity; 4 | import com.modulo7.common.utils.Modulo7Utils; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by asanyal on 10/13/15. 14 | * 15 | * N Gram similarity measure indoctrinated in Modulo7 using the sum common measure 16 | * measure as defined in NLP literature 17 | */ 18 | public class SCMNGramSimilarity implements AbstractVoiceSimilarity { 19 | 20 | // Number of grams, default to 3 21 | private int N = 3; 22 | 23 | /** 24 | * SCMNGramSim 25 | * @param n 26 | */ 27 | public SCMNGramSimilarity(final int n) { 28 | N = n; 29 | } 30 | 31 | /** 32 | * SCMNGramSim 33 | */ 34 | public SCMNGramSimilarity() { 35 | } 36 | 37 | @Override 38 | public double getSimilarity(final Voice first, final Voice second) { 39 | 40 | // Compute the distinct N grams in the first voice 41 | final Map distinctTrigramsInOne = new HashMap<>(); 42 | 43 | // Compute the distinct N grams in the second voice 44 | final Map distinctTrigramsInTwo = new HashMap<>(); 45 | 46 | final String firstSetDoc = first.getDocumentRepresentation(); 47 | final String secondSetDoc = second.getDocumentRepresentation(); 48 | 49 | String[] firstSplit = firstSetDoc.split(" "); 50 | String[] secondSplit = secondSetDoc.split(" "); 51 | 52 | for (int i = 0; i < firstSplit.length - N; i++) { 53 | String ngram = ""; 54 | for (int k = i; k < i + N; k++) 55 | ngram += firstSplit[k]; 56 | Modulo7Utils.addToCount(ngram, distinctTrigramsInOne); 57 | } 58 | 59 | for (int i = 0; i < secondSplit.length - N; i++) { 60 | String ngram = ""; 61 | for (int k = i; k < i + N; k++) 62 | ngram += secondSplit[k]; 63 | Modulo7Utils.addToCount(ngram, distinctTrigramsInTwo); 64 | } 65 | 66 | final Set commonTrigrams = new HashSet<>(distinctTrigramsInOne.keySet()); 67 | commonTrigrams.retainAll(distinctTrigramsInTwo.keySet()); 68 | 69 | int trigramSum = (Modulo7Utils.sumOverNGramFreqs(distinctTrigramsInOne, commonTrigrams) + 70 | Modulo7Utils.sumOverNGramFreqs(distinctTrigramsInTwo, commonTrigrams)); 71 | 72 | return (double) trigramSum / (firstSplit.length + secondSplit.length - 2*(N - 1)); 73 | } 74 | } -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/contour/voicecontour/NaturalContour.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.contour.voicecontour; 2 | 3 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 4 | import com.modulo7.common.interfaces.AbstractContour; 5 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 6 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 7 | import org.apache.log4j.Logger; 8 | 9 | import java.util.LinkedHashMap; 10 | 11 | /** 12 | * Created by asanyal on 9/8/15. 13 | * 14 | * Contour extremum notes are computed and returned as elements of the contour 15 | * consider three voice instants : n_i , n_{i-1} and n_{i+1}, natural contour elements 16 | * are those in which n_i is either higher or lower than both n_{i-1} and n_{i+1} simultaneously 17 | */ 18 | public class NaturalContour implements AbstractContour { 19 | 20 | // Logger for natural contour 21 | private static final Logger logger = Logger.getLogger(NaturalContour.class); 22 | 23 | public NaturalContour() { 24 | 25 | } 26 | 27 | /** 28 | * Gets the voice representation of the natural contour only exressing the 29 | * contour extremum notes 30 | * 31 | * @param voice 32 | * @return 33 | */ 34 | @Override 35 | public LinkedHashMap getContourRepresentaionOfVoice(final Voice voice) { 36 | LinkedHashMap contourExtemumNotes = new LinkedHashMap<>(); 37 | 38 | int voiceInstantIndex = 0; 39 | final int maxVoiceInstantIndex = voice.getNumVoiceInstantsOfVoice(); 40 | 41 | for (final VoiceInstant voiceInstant : voice.getVoiceSequence()) { 42 | 43 | if (voiceInstantIndex >= 1 && voiceInstantIndex < maxVoiceInstantIndex - 1) { 44 | final VoiceInstant nMinusOne = voice.getVoiceInstantAtPostion(voiceInstantIndex - 1); 45 | final VoiceInstant nPlusOne = voice.getVoiceInstantAtPostion(voiceInstantIndex + 1); 46 | 47 | try { 48 | final boolean isAllBelow = VoiceInstant.isLowerPitch(voiceInstant, nMinusOne) && 49 | VoiceInstant.isLowerPitch(voiceInstant, nPlusOne); 50 | 51 | final boolean isAllAbove = VoiceInstant.isHigherPitch(voiceInstant, nMinusOne) && 52 | VoiceInstant.isHigherPitch(voiceInstant, nPlusOne); 53 | 54 | if (isAllAbove || isAllBelow) { 55 | contourExtemumNotes.put(voiceInstantIndex, voiceInstant); 56 | } 57 | } catch (Modulo7WrongNoteType e) { 58 | logger.error(e.getMessage()); 59 | } 60 | } 61 | voiceInstantIndex++; 62 | } 63 | 64 | return contourExtemumNotes; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/genreestimation/WeightedGenreEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.genreestimation; 2 | 3 | import com.modulo7.pureresearch.lastfm.SongBagLyricsGenreMap; 4 | import com.modulo7.pureresearch.metadataestimation.tagestimation.TagEstimation; 5 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 6 | 7 | import java.util.*; 8 | 9 | /** 10 | * Created by asanyal on 12/23/15. 11 | * 12 | * Weighted genre esimation based on the number of top documents assumed as relevant 13 | */ 14 | public class WeightedGenreEstimation extends GenreEstimation { 15 | 16 | // Number of top documents that are assumed to be relevant 17 | private int topDocs; 18 | 19 | /** 20 | * Tag estimator default constructor 21 | * 22 | * @param testSet 23 | * @param trainSet 24 | * @param topDocNum 25 | */ 26 | public WeightedGenreEstimation(final Set testSet, final Set trainSet, final int topDocNum) { 27 | super(testSet, trainSet); 28 | this.topDocs = topDocNum; 29 | } 30 | 31 | @Override 32 | public Map> getEstimatedGenres() { 33 | // Init an estimated tags return object 34 | final Map> estimatedGenres = new HashMap<>(); 35 | 36 | for (final SongBagLyricsGenreMap dataElem : testSet) { 37 | final BagOfWordsDataElement bogTest = dataElem.getBagOfWords(); 38 | final Map weightedGenreLabels = new HashMap<>(); 39 | 40 | for (final SongBagLyricsGenreMap trainElem : trainSet) { 41 | final BagOfWordsDataElement bogTrain = trainElem.getBagOfWords(); 42 | final double simVal = TagEstimation.simVal(bogTest, bogTrain, SIM_CHOICE); 43 | weightedGenreLabels.put(simVal, trainElem); 44 | } 45 | 46 | // A kind of a hack here, double equality is so rare, that just sorting over key is sufficient for our work 47 | // and we dont have to pedantic over sorting the entire object, i am getting lazy so wont make a new comparator 48 | List allSims = new ArrayList<>(weightedGenreLabels.keySet()); 49 | Collections.sort(allSims, Collections.reverseOrder()); 50 | 51 | Set unionOfGenres = new HashSet<>(); 52 | int maxIndex = Math.min(topDocs, allSims.size()); 53 | 54 | for (int i = 0; i < maxIndex; i++) { 55 | Double val = allSims.get(i); 56 | SongBagLyricsGenreMap lyricsGenreMap = weightedGenreLabels.get(val); 57 | unionOfGenres.addAll(lyricsGenreMap.getLabels().getGenreList()); 58 | } 59 | 60 | estimatedGenres.put(dataElem, unionOfGenres); 61 | } 62 | 63 | return estimatedGenres; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/musictheorymodels/IntervalQuantity.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.musictheorymodels; 2 | 3 | /** 4 | * A declaration of all the intervals present in western music theory 5 | */ 6 | public enum IntervalQuantity { 7 | 8 | PERFECT_UNISON(0), 9 | MINOR_SECOND(1), 10 | MAJOR_SECOND(2), 11 | MINOR_THIRD(3), 12 | MAJOR_THIRD(4), 13 | PERFECT_FOURTH(5), 14 | AUGMENTED_FOURTH(6), 15 | DIMINISHED_FIFTH(6), 16 | PERFECT_FIFTH(7), 17 | AUGMENTED_FIFTH(8), 18 | MINOR_SIXTH(8), 19 | MAJOR_SIXTH(9), 20 | MINOR_SEVENTH(10), 21 | MAJOR_SEVENTH(11), 22 | PERFECT_OCTAVE(12); 23 | 24 | // The octave associated with this node 25 | private int intervalQuantity; 26 | 27 | // The interval quality associated with the 28 | private IntervalQuality intervalQuality; 29 | 30 | // The interval type associated with this interval 31 | private IntervalType intervalType; 32 | 33 | // The number of distinct intervals that are present in the interval 34 | private static final int NUMBER_OF_DISTINCT_INTERVALS = 12; 35 | 36 | /** 37 | * Basic constructor with only interval quantity 38 | * @param intervalQuantity 39 | */ 40 | IntervalQuantity(final int intervalQuantity) { 41 | this.intervalQuantity = intervalQuantity; 42 | inferIntervalQuality(); 43 | } 44 | 45 | /** 46 | * Infer the interval Quality given the quantity 47 | */ 48 | private void inferIntervalQuality() { 49 | if (intervalQuantity == 1 || 50 | intervalQuantity == 3 || 51 | intervalQuantity == 8 || 52 | intervalQuantity == 10) { 53 | 54 | intervalQuality = IntervalQuality.MINOR; 55 | } else if (intervalQuantity == 2 || 56 | intervalQuantity == 4 || 57 | intervalQuantity == 9 || 58 | intervalQuantity == 11) { 59 | 60 | intervalQuality = IntervalQuality.MAJOR; 61 | } else if (intervalQuantity == 0 || 62 | intervalQuantity == 5 || 63 | intervalQuantity == 7 || 64 | intervalQuantity == 12) { 65 | intervalQuality = IntervalQuality.PERFECT; 66 | } else if (intervalQuantity == 6) { 67 | intervalQuality = IntervalQuality.AUGMENTED; 68 | } 69 | } 70 | 71 | /** 72 | * Getter for interval quantity 73 | * @return 74 | */ 75 | public int getQuantity() { 76 | return intervalQuantity; 77 | } 78 | 79 | /** 80 | * Getter for interval quality 81 | * @return 82 | */ 83 | public IntervalQuality getIntervalQuality() { 84 | return intervalQuality; 85 | } 86 | 87 | /** 88 | * Gets the interval type of this interval 89 | * @return 90 | */ 91 | public IntervalType getIntervalType() { 92 | return intervalType; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/musicstatmodels/vectorspacemodels/vectorspacerepresentations/songvectors/TonalHistogram.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.musicstatmodels.vectorspacemodels.vectorspacerepresentations.songvectors; 2 | 3 | import com.modulo7.common.exceptions.Modulo7BadIntervalException; 4 | import com.modulo7.common.exceptions.Modulo7WrongNoteType; 5 | import com.modulo7.common.interfaces.AbstractSongVector; 6 | import com.modulo7.musicstatmodels.musictheorymodels.Interval; 7 | import com.modulo7.musicstatmodels.musictheorymodels.IntervalQuantity; 8 | import com.modulo7.musicstatmodels.representation.polyphonic.Song; 9 | import com.modulo7.musicstatmodels.representation.monophonic.Voice; 10 | import com.modulo7.musicstatmodels.representation.monophonic.VoiceInstant; 11 | import com.modulo7.musicstatmodels.vectorspacemodels.datastructures.TonalHistogramData; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * Created by asanyal on 8/29/15. 17 | * 18 | * A tonal intervalHistogram data structure, containing absolute counts 19 | * of a tonal intervalHistogram 20 | * 21 | */ 22 | public class TonalHistogram implements AbstractSongVector { 23 | 24 | // Internal intervalHistogram representation 25 | private TonalHistogramData intervalHistogram; 26 | 27 | /** 28 | * Default constructor for tonal histogram and the only one present 29 | */ 30 | public TonalHistogram() { 31 | intervalHistogram = new TonalHistogramData(); 32 | } 33 | 34 | @Override 35 | public void computeVectorRepresentation(final Song song) { 36 | for (Voice voice : song.getVoices()) { 37 | List voiceInstants = voice.getVoiceSequence(); 38 | 39 | /** 40 | * Acquire each of the voice instants and if 41 | */ 42 | for (int i = 0; i < voiceInstants.size() - 1; i++) { 43 | VoiceInstant instant = voiceInstants.get(i); 44 | VoiceInstant nextInstant = voiceInstants.get(i + 1); 45 | 46 | try { 47 | // Compute intervals 48 | IntervalQuantity intervalQuantity = Interval.getInterval(instant, nextInstant).getIntervalQuantity(); 49 | addIntervalToHistogram(intervalQuantity); 50 | } catch (Modulo7WrongNoteType | Modulo7BadIntervalException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | public TonalHistogramData getInternalRepresentation() { 59 | return intervalHistogram; 60 | } 61 | 62 | /** 63 | * Helper method to add interval to intervalHistogram 64 | * 65 | * @param interval 66 | */ 67 | private synchronized void addIntervalToHistogram(final IntervalQuantity interval) { 68 | Integer count = intervalHistogram.getData(interval); 69 | 70 | if (count == null) { 71 | count = 0; 72 | } 73 | 74 | intervalHistogram.setData(interval, count + 1); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/modulo7/pureresearch/metadataestimation/tagestimation/WeightedTagEstimation.java: -------------------------------------------------------------------------------- 1 | package com.modulo7.pureresearch.metadataestimation.tagestimation; 2 | 3 | import com.modulo7.pureresearch.lastfm.SongBagLyricsAndMetadata; 4 | import com.modulo7.pureresearch.musicmatch.BagOfWordsDataElement; 5 | 6 | import java.io.IOException; 7 | import java.util.*; 8 | 9 | /** 10 | * Created by asanyal on 12/11/15. 11 | * 12 | * A more sophisticated tag estimation strategy which takes into account the weights of the tags 13 | * along with the similarity order 14 | */ 15 | public class WeightedTagEstimation extends TagEstimation { 16 | 17 | /** 18 | * Default deserialization constructor for lyrics map to tags 19 | * 20 | * @param lyricsTagMapSerialized 21 | */ 22 | public WeightedTagEstimation(final String lyricsTagMapSerialized) throws IOException, ClassNotFoundException { 23 | super(lyricsTagMapSerialized); 24 | } 25 | 26 | /** 27 | * Naive tag estimator 28 | * @param testSet 29 | * @param trainSet 30 | */ 31 | public WeightedTagEstimation(final Set testSet, final Set trainSet) { 32 | super(testSet, trainSet); 33 | } 34 | 35 | @Override 36 | public Map> getEstimatedTags() { 37 | 38 | final int trainDataSize = trainSet.size(); 39 | 40 | // Init an estimated tags return object 41 | final Map> estimatedTags = new HashMap<>(); 42 | 43 | for (final SongBagLyricsAndMetadata dataElem : testSet) { 44 | final BagOfWordsDataElement bogTest = dataElem.getBagOfWords(); 45 | final Map> weightedTagSet = new HashMap<>(); 46 | 47 | for (final SongBagLyricsAndMetadata trainElem : trainSet) { 48 | final BagOfWordsDataElement bogTrain = trainElem.getBagOfWords(); 49 | final Map trainTags = trainElem.getTags(); 50 | final double simVal = simVal(bogTest, bogTrain, SIM_CHOICE); 51 | weightedTagSet.put(simVal, trainTags); 52 | } 53 | 54 | final List sortedSims = new ArrayList<>(weightedTagSet.keySet()); 55 | int counter = 0; 56 | 57 | for (final Double val : sortedSims) { 58 | final Map weightedSims = weightedTagSet.get(val); 59 | final double alpha = (double) (trainDataSize - counter) / trainDataSize; 60 | 61 | for (Map.Entry weightedSim : weightedSims.entrySet()) { 62 | Double newSim = weightedSim.getValue() * alpha; 63 | weightedSim.setValue(newSim.intValue()); 64 | } 65 | 66 | counter++; 67 | 68 | estimatedTags.put(dataElem, weightedTagSet.get(val)); 69 | } 70 | } 71 | 72 | return estimatedTags; 73 | } 74 | } 75 | --------------------------------------------------------------------------------