Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,29 @@ __pycache__
.idea
data
runs
output

.vscode

# Mac
.DS_Store

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ In order to test on the Maestro dataset's test split instead of the MAPS databas
python evaluate.py runs/model/model-100000.pt Maestro test
```

You can download a pretrained model [here](https://drive.google.com/file/d/1Mj2Em07Lvl3mvDQCCxOYHjPiB-S0WGT1/view?usp=sharing) and run `transcribe.py` to transcribe piano audio files:

```bash
python transcribe.py model-500000.pt <path to audio files> --save-path output/
```

## Implementation Details

This implementation contains a few of the additional improvements on the model that were reported in the Maestro paper, including:
Expand All @@ -71,5 +77,3 @@ Meanwhile, this implementation does not include the following features:
* Harmonically decaying weights on the frame loss

Despite these, this implementation is able to achieve a comparable performance to what is reported on the Maestro paper as the performance without data augmentation.


47 changes: 26 additions & 21 deletions onsets_and_frames/midi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import sys

import mido
import pretty_midi
import numpy as np
import collections
from joblib import Parallel, delayed
from mido import Message, MidiFile, MidiTrack
from mir_eval.util import hz_to_midi
from tqdm import tqdm

Expand Down Expand Up @@ -60,28 +61,32 @@ def save_midi(path, pitches, intervals, velocities):
intervals: list of (onset_index, offset_index)
velocities: list of velocity values
"""
file = MidiFile()
track = MidiTrack()
file.tracks.append(track)
ticks_per_second = file.ticks_per_beat * 2.0
file = pretty_midi.PrettyMIDI()
piano_program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano')
piano = pretty_midi.Instrument(program=piano_program)

events = []
# Remove overlapping intervals (end time should be smaller of equal start time of next note on the same pitch)
intervals_dict = collections.defaultdict(list)
for i in range(len(pitches)):
events.append(dict(type='on', pitch=pitches[i], time=intervals[i][0], velocity=velocities[i]))
events.append(dict(type='off', pitch=pitches[i], time=intervals[i][1], velocity=velocities[i]))
events.sort(key=lambda row: row['time'])

last_tick = 0
for event in events:
current_tick = int(event['time'] * ticks_per_second)
velocity = int(event['velocity'] * 127)
if velocity > 127:
velocity = 127
pitch = int(round(hz_to_midi(event['pitch'])))
track.append(Message('note_' + event['type'], note=pitch, velocity=velocity, time=current_tick - last_tick))
last_tick = current_tick

file.save(path)
pitch = int(round(hz_to_midi(pitches[i])))
intervals_dict[pitch].append((intervals[i], i))
for pitch in intervals_dict:
interval_list = intervals_dict[pitch]
interval_list.sort(key=lambda x: x[0][0])
for i in range(len(interval_list) - 1):
# assert interval_list[i][1] <= interval_list[i+1][0], f'End time should be smaller of equal start time of next note on the same pitch. It was {interval_list[i][1]}, {interval_list[i+1][0]} for pitch {key}'
interval_list[i][0][1] = min(interval_list[i][0][1], interval_list[i+1][0][0])

for pitch in intervals_dict:
interval_list = intervals_dict[pitch]
for interval,i in interval_list:
pitch = int(round(hz_to_midi(pitches[i])))
velocity = int(127*min(velocities[i], 1))
note = pretty_midi.Note(velocity=velocity, pitch=pitch, start=interval[0], end=interval[1])
piano.notes.append(note)

file.instruments.append(piano)
file.write(path)


if __name__ == '__main__':
Expand Down
Loading