#!/usr/bin/env python

import scipy
import click
import pandas as pd
import numpy as np
import pretty_midi

from midify.resample import resample
from midify.find_peaks import find_peaks, find_first_peak
from midify.notes import freqs

@click.command(no_args_is_help=True)
@click.argument('input')
@click.option('--output', help='Output MIDI file', default='output.mid')
@click.option('--peak-min-height', help='Minimum size of a peak to be considered a individual note', default=0.2)
@click.option('--peak-threshold', help='Minimum distance from the neighbours to be considered a peak', default=0.001)
@click.option('--peak-min-distance', help='Minimum distance between peaks', default=600)
@click.option('--note-sample-size', help='How many samples use to identify a note', default=1024)
@click.option('--note-attack-shift', help='How many samples ignore from the start of a note (ignore attack)', default=20)
@click.option('--note-frequency-peak-min-height', help='Minimum height of a peak in the frequency spectrum to be considered a note', default=10)
@click.option('--note-duration', help='The amount of time the MIDI notes generated should last', default=0.5)
def midify(input, output, peak_min_height, peak_threshold, peak_min_distance, note_sample_size, note_attack_shift, note_frequency_peak_min_height, note_duration):
    new_rate = 6000

    rate, data = scipy.io.wavfile.read(input)
    resampled = resample(data, rate, new_rate=new_rate)

    peaks = find_peaks(resampled, height=peak_min_height, threshold=peak_threshold, min_distance=peak_min_distance)
    notes_samples = np.array([resampled[p + note_attack_shift: p + note_attack_shift + note_sample_size ] for p in peaks])

    notes_fft = np.array([np.abs(scipy.fft.fft(n))[0:512] for n in notes_samples])
    notes_freqs = np.array([find_first_peak(x, note_frequency_peak_min_height) * new_rate / note_sample_size for x in notes_fft])

    notes = np.array([np.argmin(np.abs(freqs - f)) for f in notes_freqs])

    mf = pretty_midi.PrettyMIDI()
    piano_program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano')
    piano = pretty_midi.Instrument(program=piano_program)
    for note_number, peak in zip(notes,peaks):
        start = peak/new_rate
        note = pretty_midi.Note(velocity=100, pitch=note_number, start=start, end=start + note_duration)
        piano.notes.append(note)
    mf.instruments.append(piano)

    mf.write(output)

if __name__ == "__main__":
    midify()
