import Foundation

// MARK: - Note

/// A single musical note or rest with a pitch and duration.
struct Note: Equatable, Hashable {
    let pitch: Pitch?       // nil for rests
    let duration: Duration
    let isRest: Bool

    /// Create a pitched note
    static func pitched(_ pitch: Pitch, duration: Duration) -> Note {
        return Note(pitch: pitch, duration: duration, isRest: false)
    }

    /// Create a rest
    static func rest(duration: Duration) -> Note {
        return Note(pitch: nil, duration: duration, isRest: true)
    }

    /// Duration in beats (quarter note = 1 beat)
    var beats: Double {
        return duration.beats
    }

    /// Duration in seconds at a given BPM
    func seconds(atBPM bpm: Double) -> Double {
        return duration.seconds(atBPM: bpm)
    }

    /// Frequency in Hz (0 for rests)
    var frequency: Double {
        return pitch?.frequency ?? 0.0
    }

    /// MIDI note number (0 for rests)
    var midiNumber: Int {
        return pitch?.midiNumber ?? 0
    }
}

extension Note: CustomStringConvertible {
    var description: String {
        if isRest {
            return "R \(duration)"
        } else if let pitch = pitch {
            return "\(pitch) \(duration)"
        } else {
            return "? \(duration)"
        }
    }
}
