diff --git a/CHANGELOG.md b/CHANGELOG.md index 5160ff2..f353f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +# v2.7.0 +* New meta event type `SequencerSpecificEvent`. +* Implement `Base.empty!(::MIDITrack)` and `Base.isempty(t::MIDITrack)`. # v2.6.0 * New functions `metric_time`. * New functions `duration_metric_time`. diff --git a/Project.toml b/Project.toml index 616ad22..480f7ab 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MIDI" uuid = "f57c4921-e30c-5f49-b073-3f2f2ada663e" repo = "https://github.com/JuliaMusic/MIDI.jl.git" -version = "2.6.0" +version = "2.7.0" [deps] FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" diff --git a/src/events.jl b/src/events.jl index fc22b31..09fc777 100644 --- a/src/events.jl +++ b/src/events.jl @@ -60,7 +60,12 @@ const MIDI_EVENTS_DEFS = Dict( decode = :(Int.(data)), encode = :(UInt8.([event.semitones, event.scale])) ), - + 0x7f => ( + type = :SequencerSpecificEvent, + fields = ["ssdata::Vector{UInt8}"], + decode = :(data), + encode = :(event.ssdata) + ), # MidiEvents 0x80 => ( type = :NoteOffEvent, @@ -124,12 +129,14 @@ function define_type(type, fields, decode, encode_, supertype, typebyte) $(fields...) end - """ $($type)(dT::Int, typebyte::UInt8, data::Vector{UInt8}) - Returns a `$($type)` event from it's byte representation. - The parameter `typebyte::UInt8` is its's $(($type <: MetaEvent) ? "metatype" : "status") byte. - """ - function $type(dT::Int, typebyte::UInt8, data::Vector{UInt8}) - $type(dT, typebyte, $decode...) + if !($type.types[end] <: AbstractArray) + """ $($type)(dT::Int, typebyte::UInt8, data::Vector{UInt8}) + Returns a `$($type)` event from it's byte representation. + The parameter `typebyte::UInt8` is its's $(($type <: MetaEvent) ? "metatype" : "status") byte. + """ + function $type(dT::Int, typebyte::UInt8, data::Vector{UInt8}) + $type(dT, typebyte, $decode...) + end end if $type <: MetaEvent @@ -407,3 +414,13 @@ The `PitchBendEvent` informs a MIDI device to modify the pitch in a specific cha * `pitch::Int` : Value of the pitch bend. """ PitchBendEvent + +""" SequencerSpecificEvent <: MetaEvent +The `SequencerSpecificEvent` is used to store vendor-proprietary data in a MIDI file. + +## Fields: +* `dT::Int` : Delta time in ticks. +* `metatype::UInt8` : Meta type byte of the event. +* `ssdata::Vector{UInt8}` : Vendor-proprietary data. +""" +SequencerSpecificEvent \ No newline at end of file diff --git a/src/miditrack.jl b/src/miditrack.jl index 82ef160..6909a6a 100644 --- a/src/miditrack.jl +++ b/src/miditrack.jl @@ -7,6 +7,8 @@ Track chunks begin with four bytes spelling out "MTrk", followed by the length (in bytes) of the track (see [`readvariablelength`](@ref)), followed by a sequence of events. + +`MIDITrack` implements the `isempty` and `empty!` functions. """ mutable struct MIDITrack events::Vector{TrackEvent} @@ -21,6 +23,8 @@ function Base.show(io::IO, t::MIDITrack) print(io, "$(L)-event MIDITrack: $M MIDI, $T Meta, $X Sysex") end +Base.empty!(t::MIDITrack) = empty!(t.events) +Base.isempty(t::MIDITrack)::Bool = isempty(t.events) function readtrack(f::IO) diff --git a/test/SequencerSpecific.mid b/test/SequencerSpecific.mid new file mode 100644 index 0000000..cdda7f3 Binary files /dev/null and b/test/SequencerSpecific.mid differ diff --git a/test/metaevent.jl b/test/metaevent.jl index 5ccba2f..b77f4ec 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -31,4 +31,22 @@ @test_throws errtype MIDI.readsysexevent(Int(input[1]), IOBuffer(input[2:length(input)])) end end + + @testset "SequencerSpecificEvent" begin + midi = load("SequencerSpecific.mid") + sse = midi.tracks[1].events[1] + @test sse isa MIDI.SequencerSpecificEvent + sse.ssdata == [0x11, 0x21, 0x53, 0x1F] + + sse = MIDI.SequencerSpecificEvent(0, 0x7f, [0x11, 0x21, 0x53, 0x1F]) + @test sse.ssdata == [0x11, 0x21, 0x53, 0x1F] + end + + @testset "check empty" begin + midi = load(testmidi()) + track = midi.tracks[1] + @test !isempty(track) + empty!(track) + @test isempty(track) + end end