'''
This is the module you'll submit to the autograder.

There are several function definitions, here, that raise RuntimeErrors.  You should replace
each "raise RuntimeError" line with a line that performs the function specified in the
function's docstring.
'''

import numpy as np

def level_to_amplitude(levels):
    '''
    amplitudes = level_to_amplitudes(levels)

    levels - any array or list of levels, in dB
    amplitudes - a numpy array or list, of the same length, containing amplitudes
    '''
    raise RuntimeError("You need to write this part!")

def create_phasors(amplitudes, phases):
    '''
    phasors = create_phasors(amplitudes, phases)
    
    phases - an array or list of the same length, containing phase angles, in radians
    amplitudes - an array or list of amplitudes
    phasors - the resulting phasors = amplitude*exp(j*phases)
    '''
    raise RuntimeError("You need to write this part!")

def synthesize_note(z, F0, Fs, d):
    '''
    x = synthesize_note(z, F0, Fs, d)
    
    z (array of length N) - an array or list of phasors, giving the amplitude and phase of each harmonic
    F0 (scalar) - the fundamental frequency, in Hertz
    Fs (scalar) - the sampling frequency, in samples/second
    d (scalar) - the duration, in seconds
    x (array of length Fs*d) - the synthesized signal
    
    This function creates one harmonic for each element of z, then adds them together to generate x.
    '''
    raise RuntimeError("You need to write this part!")

import note2f0
def names_to_fundamentals(names):
    '''
    F0 = names_to_fundamentals(names)
    
    names - a list of names of notes, e.g., ['D#4','G#4','F4','G4','F4']
    fundamentals - a list of the corresponding fundamental frequencies, in Hertz, e.g., [311.13, 415.3, 349.23, 392.0, 349.23]
    '''
    raise RuntimeError("You need to write this part!")

def synthesize_song(fundamentals, beats, bpm, Fs, phasors):
    '''
    song = synthesize_song(fundamentals, beats, bpm, Fs, phasors)
    
    fundamentals (array) - fundamental frequencies of the notes to be played
    beats (array) - duration of each note, in beats, e.g., [1,3/4,1/4,1,1]
    bpm (scalar) - number of beats per minute
    Fs (scalar) - number of samples per second
    phasors (list or array) - amplitude and phase of each harmonic
    song (numpy array)  - the returned song
    
    This function should first use beats and bpm to figure out the durations of the notes, in seconds.
    Then, for each note, it should:
        (1) call synthesize_note, to synthesize the note
        (2) call np.hanning, to create a hanning window, and multiply it by the note
        (3) call np.concatenate to concatenate the note  onto the song
    '''
    raise RuntimeError("You need to write this part!")
