#!/usr/bin/env python3

import os
import re
import tempfile
import math
import random
import numpy as np
from midiutil.MidiFile import MIDIFile
from midi import Note, GM_PATCHES


class Sample:
    SOUNDFONT = "soundfont.sf2"

    @staticmethod
    def note_to_freq(note, octave, a_440=440.0):
        note_map = {}
        for i, note_name in enumerate(Note.names):
            note_map[note_name] = i

        key = note_map[note] + ((octave - 1) * 12) + 1
        return a_440 * pow(2, (key - 46) / 12.0)

    def __init__(self, name, program=0, key='A', octave=4, volume=100, tempo=60):
        self.name = name
        self.mid_filename = name + '.mid'
        self.tmp_filename = self.name + "-" + "full" + ".wav"

        self.key = key
        self.octave = octave
        self.note = str(key)+str(octave)
        self.freq = Sample.note_to_freq(key, octave)

        self.file = MIDIFile(1, adjust_origin=True)
        self.file.addTempo(0, 0, tempo)
        self.file.addProgramChange(0, 0, 0, program)
        self.file.addNote(0, 0, Note.note(self.note), 0, 1, volume)

    def save(self):
        with open(self.mid_filename, "wb") as out:
            self.file.writeFile(out)

    def make_wav(self):
        self.save()
        os.system("fluidsynth -l -i -a file %s %s -F %s -r 44100" %
                  (Sample.SOUNDFONT, self.mid_filename, self.tmp_filename))

    def transform_wav(self, suffix, start_s=0, duration=1, pitch_shift_hz=0, resample_hz=44100, resample_bits=16):
        shift_cents = 0
        if pitch_shift_hz != 0:
            shift_cents = 1200.0 * \
                math.log((self.freq + pitch_shift_hz) / self.freq, 2)

        self.new_freq = self.freq + pitch_shift_hz

        wav_file = self.name + "-" + \
            "%.3f" % (self.new_freq) + "-" + "S" + \
            str(pitch_shift_hz) + "-" + suffix + ".wav"
        print("Writing ", wav_file, "with sample rate",
              resample_hz, "and bit depth", resample_bits, ("(shift %s)" % shift_cents))

        os.system("sox -t raw -r 44100 -e signed -b 16 -c 2 %s -r %s -b %s %s norm -0.1 pitch %s remix 2 trim %f %f" %
                  (self.tmp_filename, resample_hz, resample_bits, wav_file, shift_cents, start_s, duration))

    def clean(self):
        # Keep only transformed
        os.remove(self.mid_filename)  # Remove midi file
        os.remove(self.tmp_filename)  # Remove -full .wav file