Music is visualized everyday – but is there any accuracy to its representation?

Can sound be accurately represented? If so, what does it look like? How is accuracy measured? While not fully satisfied with the answers found to these questions, Python’s mido package shed light on the how sound and color may be linked through defining binned heatmaps by key signature.

Decoding

The exercise began by decoding openly-sourced MIDI data.

  1. Note Number (Pitch): Represents pitch values from 0 to 127, with 60 as Middle C. Mido interprets it using the note property, providing easy access to note names and octaves.
  2. Velocity: Ranges 0 to 127, indicating key strike intensity. Mido extracts velocity through the velocity property, allowing precise control over note dynamics.
  3. Control Change: Carries values 0 to 127, modulating parameters like volume. Mido dissects control change messages using the control attribute for targeted parameter adjustment.
  4. Program Change: Values 0 to 127 for instrument presets. Mido interprets program change with the program attribute, facilitating dynamic instrument selection.
  5. Pitch Bend: Employs two 7-bit values for pitch modulation. Mido decodes pitch bend using the pitch attribute, capturing nuanced pitch variations.
  6. Aftertouch (Pressure): Ranges 0 to 127, measuring key pressure. Mido extracts aftertouch data through the aftertouch attribute, enabling sensitivity adjustments.
  7. Channel: MIDI channels 1 to 16. Mido segregates channels using the channel property, simplifying the handling of multiple independent streams of MIDI data.

In this case, Tame Impala’s Elephant was analyzed for its extract notes, their timing, velocity, key signature, and pitch bend to visualize the distribution of notes.

Keys determined histogram coloration with bars representative of note frequency colored consistently by note across scales.

Heatmaps

The collected note data was used to create a heatmap using seaborn and matplotlib. The heatmap visualizes note occurrences over time, providing admittedly lean but accurate insights into the composition’s structure.

Normalization

To enhance the visual clarity of the heatmap, then data was normalized to range of note values present in the song. MIDI has 128 possible outputs but 88 typically represented values. Most songs, have between 15 and 60. Noizo’s Baby Baby, for example, has 47.

Time | Rich Homie Quan & Young Thug
Looping

Due to popular curiosity, the process was optimized using a for loop to extract MIDI inputs from a folder path and output PNGs to specified folder. Additionally, to allow for the comparison of musical attributes among songs, all songs obtained from a folder path had their musical attributes exported to a CSV…for further analysis.

Specifying Color

In heatmap mass production, the question of color accuracy reappeared. Colors were initially sourced from the University of Minnesota. Their matching to note values failed in songs which I later discovered to be in B major like the Arctic Monkeys’ Dancing Shoes or Cage the Elephant’s Back Against the Wall.

Original | C Major to F Major
Methodology

On a quest to redefine the colors I initially entrusted to note values, I kept seaborn and matplotlib close by. Trial and error with plotly softened the color outputs from the initial heavy saturations to a new mapping closer to the spectral cmap.

  • Import Statements
    • mido
    • pandas
    • matplotlib (pyplot, colors)
    • seaborn
    • os
    • numpy
  • Variable Definitions
    • folder path, file title
    • def process_midi(midi_file, current_tempo, ticks_per_beat, current_time_in_seconds, current_key_signature, current_pitch_bend, current_minute, minute_data, midi_data, heatmap_data)
  • Utility Functions
    • def midi_to_key_with_major(note_number)
    • def create_colormap(hex_color)
  • Main Function
    • def main():
      • current_tempo, current_time_in_seconds, current_key_signature, current_pitch_bend, current_minute, midi_data, heatmap_data = process_midi( midi_file, current_tempo, ticks_per_beat, current_time_in_seconds, current_key_signature, current_pitch_bend, current_minute, minute_data, midi_data, heatmap_data )
      • heatmap = heatmap_data.pivot_table(index='Note', columns='TimeInSeconds', aggfunc='size', fill_value=0)
      • key_colors = {}
      • sns.histplot(data=heatmap_data, x='Note', hue='Note', multiple="stack", palette=key_colors, edgecolor='black')
      • output_file_path_svg = f'[path]\midis_to_csvs{midi_file_title[:-4]}_normalized.svg'
Adjusted | C Major to F Major
Conclusion

While unable to confirm if sound can accurately be represented, the mido package can be leveraged to develop an individual’s note palette. More work is to be done to add complexity to visualizations and elucidate patterns from pitch and channel variables.

This methodology is valuable for musicians, composers, or anyone interested in exploring the structure and visual translation of MIDI-based music compositions. It bridges the gap between raw MIDI data and meaningful visualizations, enhancing the interpretability of musical content.