<commit_before>//
//  DIYSeq.swift
//  AudioKit
//
//  Created by <NAME> on 5/8/19.
//  Copyright © 2019 AudioKit. All rights reserved.
//

open class DIYSeq {

    open var tracks = [DIYSeqTrack]()
    open var tempo: BPM {
        get { return tracks.first?.tempo ?? 0 }
        set { for track in tracks { track.tempo = newValue } }
    }

    open var length: Double {
        get { return tracks.max(by: { $0.length > $1.length })?.length ?? 0 }
        set { for track in tracks { track.length = newValue } }
    }

    open func play() {
        for track in tracks { track.play() }
    }

    open func add(noteNumber: MIDINoteNumber, velocity: MIDIVelocity = 127, channel: MIDIChannel = 0,
                  position: Double, duration: Double, trackIndex: Int = 0) {
        guard tracks.count > trackIndex, trackIndex >= 0 else {
            AKLog("Track index \(trackIndex) out of range (sequencer has \(tracks.count) tracks)")
            return
        }
        tracks[trackIndex].add(noteNumber: noteNumber, velocity: velocity, channel: channel,
                               position: position, duration: duration)
    }

    open func add(event: AKMIDIEvent, position: Double, trackIndex: Int = 0) {
        guard tracks.count > trackIndex, trackIndex >= 0 else {
            AKLog("Track index \(trackIndex) out of range (sequencer has \(tracks.count) tracks)")
            return
        }
        tracks[trackIndex].add(event: event, position: position)
    }

    required public init(targetNodes: [AKNode]) {
        tracks = targetNodes.enumerated().map({ DIYSeqTrack(targetNode: $0.element) })
    }

    public convenience init(targetNode: AKNode? = nil) {
        if let node = targetNode {
            self.init(targetNodes: [node])
        } else {
            self.init(targetNodes: [AKNode]())
        }
    }

    public convenience init(fromURL fileURL: URL, targetNodes: [AKNode]) {
        self.init(targetNodes: targetNodes)
        let midiFile = AKMIDIFile(url: fileURL)
        let tracks = midiFile.tracks
        if tracks.count > targetNodes.count {
            AKLog("Error: Track count and node count do not match, dropped \(tracks.count - targetNodes.count) tracks")
        }
        for node in targetNodes.enumerated() {
            let index = node.offset
            let track = tracks[index]
            for event in track.events {
                if let pos = event.positionInBeats {
                    self.tracks[index].add(event: event, position: pos)
                }
            }
        }
    }
}


/* functions from aksequencer to implement

 public convenience init(fromURL fileURL: URL) {
 open func enableLooping(_ loopLength: AKDuration) {
 open func setLoopInfo(_ duration: AKDuration, numberOfLoops: Int) {
 open func setLength(_ length: AKDuration) {
 open var length: AKDuration {
 open func setRate(_ rate: Double) {
 open func setTempo(_ bpm: Double) {
 open func addTempoEventAt(tempo bpm: Double, position: AKDuration) {
 open var tempo: Double {<commit_msg>length from midi file implemented<commit_after>//
//  DIYSeq.swift
//  AudioKit
//
//  Created by <NAME> on 5/8/19.
//  Copyright © 2019 AudioKit. All rights reserved.
//

open class DIYSeq {

    open var tracks = [DIYSeqTrack]()
    open var tempo: BPM {
        get { return tracks.first?.tempo ?? 0 }
        set { for track in tracks { track.tempo = newValue } }
    }

    open var length: Double {
        get { return tracks.max(by: { $0.length > $1.length })?.length ?? 0 }
        set { for track in tracks { track.length = newValue } }
    }

    open var loopEnabled: Bool {
        get { return tracks.first?.loopEnabled ?? false }
        set { for track in tracks { track.loopEnabled = newValue } }
    }

    open func play() {
        for track in tracks { track.play() }
    }

    open func add(noteNumber: MIDINoteNumber, velocity: MIDIVelocity = 127, channel: MIDIChannel = 0,
                  position: Double, duration: Double, trackIndex: Int = 0) {
        guard tracks.count > trackIndex, trackIndex >= 0 else {
            AKLog("Track index \(trackIndex) out of range (sequencer has \(tracks.count) tracks)")
            return
        }
        tracks[trackIndex].add(noteNumber: noteNumber, velocity: velocity, channel: channel,
                               position: position, duration: duration)
    }

    open func add(event: AKMIDIEvent, position: Double, trackIndex: Int = 0) {
        guard tracks.count > trackIndex, trackIndex >= 0 else {
            AKLog("Track index \(trackIndex) out of range (sequencer has \(tracks.count) tracks)")
            return
        }
        tracks[trackIndex].add(event: event, position: position)
    }

    required public init(targetNodes: [AKNode]) {
        tracks = targetNodes.enumerated().map({ DIYSeqTrack(targetNode: $0.element) })
    }

    public convenience init(targetNode: AKNode? = nil) {
        if let node = targetNode {
            self.init(targetNodes: [node])
        } else {
            self.init(targetNodes: [AKNode]())
        }
    }

    public convenience init(fromURL fileURL: URL, targetNodes: [AKNode]) {
        self.init(targetNodes: targetNodes)
        let midiFile = AKMIDIFile(url: fileURL)
        let tracks = midiFile.tracks
        if tracks.count > targetNodes.count {
            AKLog("Error: Track count and node count do not match, dropped \(tracks.count - targetNodes.count) tracks")
        }
        if tracks.count < targetNodes.count {
            AKLog("Error: Track count less than node count, ignoring \(targetNodes.count - tracks.count) nodes")
        }
        for index in 0..<min(targetNodes.count, tracks.count) {
            let track = tracks[index]
            for event in track.events {
                if let pos = event.positionInBeats {
                    self.tracks[index].add(event: event, position: pos)
                }
            }
            self.tracks[index].length = track.length
        }
        length = self.tracks.max(by: { $0.length > $1.length})?.length ?? 0
    }
}


/* functions from aksequencer to implement

 public convenience init(fromURL fileURL: URL) {
 open func enableLooping(_ loopLength: AKDuration) {
 open func setLoopInfo(_ duration: AKDuration, numberOfLoops: Int) {
 open func setLength(_ length: AKDuration) {
 open var length: AKDuration {
 open func setRate(_ rate: Double) {
 open func setTempo(_ bpm: Double) {
 open func addTempoEventAt(tempo bpm: Double, position: AKDuration) {
 open var tempo: Double {
{'fraction_non_alphanumeric': 0.10735068912710567, 'fraction_numerical': 0.007044410413476264, 'mean_word_length': 2.320284697508897, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3864709', 'n_tokens_mistral': 1940, 'n_tokens_neox': 1830, 'n_words': 568}