Table of Contents

    In [1]:
    import pandas as pd
    import numpy as np
    import networkx as nx
    
    In [2]:
    import plotly.graph_objects as go
    import plotly.figure_factory as ff
    import plotly.express as px
    import plotly.io as pio
    pio.templates.default = 'plotly_white'
    import webcolors as wc
    import colorsys
    
    In [3]:
    import mido
    from mido import MidiFile
    
    In [4]:
    rainbow = ['red','purple','slateblue','darkslateblue','royalblue','dodgerblue','mediumseagreen','yellowgreen','yellow','gold','orange','orangered']
    
    In [5]:
    #colormode = "sequential" 
    colormode = "fifths"
    
    In [6]:
    s = '80%'
    l = '60%'
    if colormode == "sequential": letters = ['C','B','A#','A','G#','G','F#','F','E','D#','D','C#']
    if colormode == "fifths": letters = ['C','F','A#','D#','G#','C#','F#','B','E','A','D','G']
    hues = [0,330,300,270,240,210,180,150,120,90,60,30]
    huezip = dict(zip(letters,hues))
    hsl = [f'hsl({h}, {s}, {l})' for h in hues]
    colors = dict(zip(letters,hsl))
    
    In [7]:
    freq = pd.read_csv('frequencies.csv').set_index('midi').dropna()
    notes = list(freq['note'])
    
    In [8]:
    freq['hue']=[huezip[letter] for letter in freq['letter']]
    lightmap = ['10%','20%','30%','40%','50%','60%','70%','80%','90%']
    freq['lightness']=[lightmap[int(octave)] for octave in freq['octave']]
    freq['hsl'] = [str('hsl('+str(h)+','+str(s)+','+l+')') for h,l in zip(freq['hue'],freq['lightness'])]
    
    In [9]:
    songs = ['baba','badguy','canond','clair','dancingqueen','frere','furelise','happybirthday','heartsoul','littleboxes','madworld','moonlight','moonriver','ode','swanee','twinkle','vivspring']
    
    In [10]:
    data = {}
    
    In [11]:
    def parse_midi(song):
        mid = MidiFile('audio/midi/'+song+'.mid')
        tracks = {}
        for i, track in enumerate(mid.tracks):
            t = 'track_'+str(i)
            df=pd.DataFrame(columns=['midi','note','time','tstep','letter'])
            midi = []
            time = []
            for msg in track:
                if msg.type == 'note_on':
                    midi.append(msg.note)
                    time.append(msg.time)
                if msg.type == 'note_off':
                    midi.append(msg.note)
                    time.append(msg.time)
            df['midi']=midi
            df['note']=[freq['note'][m] for m in df['midi']]
            df['letter']=[freq['letter'][m] for m in df['midi']]
            try: df['color']=[freq[freq['note']==n]['hsl'].values[0] for n in df['note']]
            except: continue
            df['time']=time
            df['tstep']=df['time'].cumsum()
            if df.shape[0]>0:
                tracks[t]=df
        data[song]=tracks
    
    In [12]:
    for song in songs: parse_midi(song)
    
    In [13]:
    def vis_dist(song,stats=['letter','note']):
        s = data[song]
        for stat in stats:
            fig = go.Figure()
            for i, track in enumerate(s):
                values = list(s[track][stat].unique())
                counts=[]
                colormap = []
                for v in values:
                    counts.append(s[track][s[track][stat]==v].shape[0])
                    if stat=='note': colormap.append(freq[freq['note']==v]['hsl'].values[0])
                    if stat=='letter': colormap.append(colors[v])
                fig.add_trace(go.Bar(x=values, y=counts,name=track,marker_color=colormap))
            fig.update_layout(title=song, showlegend=False)
            fig.show()
            fig.write_image('charts/raster/'+song+'_'+stat+'_distribution.png')
            fig.write_image('charts/vector/'+song+'_'+stat+'_distribution.svg')
    
    In [14]:
    for song in songs: vis_dist(song)