From 1a65df35fc851d243b802b4b7bb7cadf3b062f03 Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Wed, 17 Jul 2024 17:22:31 +0800 Subject: [PATCH 1/6] add SequencerSpecificEvent support --- CHANGELOG.md | 2 ++ Project.toml | 2 +- src/events.jl | 31 ++++++++++++++++++++++++------- test/SequencerSpecific.mid | Bin 0 -> 2846 bytes test/metaevent.jl | 8 ++++++++ 5 files changed, 35 insertions(+), 8 deletions(-) create mode 100755 test/SequencerSpecific.mid diff --git a/CHANGELOG.md b/CHANGELOG.md index 5160ff2..abe45f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ 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 event type `SequencerSpecificEvent`. # v2.6.0 * New functions `metric_time`. * New functions `duration_metric_time`. diff --git a/Project.toml b/Project.toml index 616ad22..ba1a274 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,7 @@ IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e" [compat] FileIO = "1" -IterTools = "1.8.0" +IterTools = "1.10.0" julia = "1" [extras] 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/test/SequencerSpecific.mid b/test/SequencerSpecific.mid new file mode 100755 index 0000000000000000000000000000000000000000..93e5a4a930f44a2f4d0353ef2aedc9e32f6fd6f9 GIT binary patch literal 2846 zcmX|DO^@To5iRX#c9k^`T!b(PL;+}kaD;`{*2+qTJtCA-Wk!60~wja9%Mj4 z27wSOfPg3&G`X;YBnX&mZutlN3I0jG`M7zl-S{w=W`9(@s(STGuU6X)5k1CV>+HK% zt3Upp=z|WuJ?s4G5BuNk@4wp6_nn!oi2h1Hw7&ldmXBK0a(|%rYmey1HJ|@~eMa=> z4))E{GqTL~yQTf`{`Ogm_{Z&*^#J4MMu(mlKkt@b^6B!|t>rU1$NKHM-G1Z(-ItGm z_ib_ZEH|p9W|>+kuRglDHv9&zGMq$ZArG8mU~5goSojq)j%dVE01bo;ij($hN?v| zF<7V|S8`>m2v6abLK&93Vq&oLWCScQ7J0z3G&U#IsF)akB(F3V)Nc5~t0lP&lispt z)k<2-Uc(RCs~JE^FFESSwCXXniv*C$prC_%WwWeohD{mB8HE`{`O z_f$Ga;p24Y(%eBs%blF7f(*4>xf-Y&B(Yp5>Vj6FDisV;XCOQ(T`g4M$lquMPd#~w zf>f%Q!Vch1Y&gP$(pJCJJ%s4XnU}^IVDD41l9&srUndB!pb@%+1JoWXpi`ff!0pKZ zX2>tb6_^RqgTT~QpS=OA9T~hC6bw&qP`aIbUgG9|kf=D|rvcMlJxuy))ob{tCRa|4 z5SJo!hlGH1U(ss;a2$JTcEFLxv=tLyNj<_>PrzboE2S+(8vyExC{?dCG);Sg791NR zAe3&48Fupy)8*nKEbuY^_ZjL;Zx9`c0pL_4s8=YCEs z#_LR$dx0Dz_Zha~*%9$_zNjpob_7{-D%WBb&efWU=R`2GY`6t(ICXY?*YF1+KVV6E zCx&ho>n@fnL5d}1x%TnJLaOW)JZj1aHcLk?x>oS=AL}bE0XEP7+g-6d>0~;ipLGsFn+7c)e}-V>l|^TEx8}flAuP zrGTT-gye|G*zRY)hSX`arFOA{D1GKK%%~?KV;8m3n})9fK67jJMf+t2eM6h@t>H?q z7Qx}=snWU!!+iv;Xe~aelz=uQlocn_fw(M>*nz_J5Q!27yMkyj5c#{ zhq>LHW=DCbMPvasxS|FN>3M0oh0m4Bj;set?zCiOd z;B%{<-wXiUt49(vcpUN#@ZZ&Q1bC@Hvn}qrhyd&cg+(q~{Bga)EvaOs{@!CQq4)^bYgZ=d`!X`^XA@T!7m9rRfp~x3r7TOC-z^GR3U# zs?SlOHcxc`QE-Gr@hC(M0rMIBtn1-*x8ZXGSJh%14o_XGQ=WEnWk|FZlWl&=%OP8m zoSbNc7SK!Z2RvHxWS!@w3)KQA`Z*bHbsC<+y7ueQRa+H&a`sSmYr)XT6g)CCbub;l z7NfxE2XvKdL~>+C7+Nr_()n`aI~i3QnZj6!!tLM*DR7w4*p~`00r{W%c!ue0-^@r}*bVyz{+53Z z)8BAy=th_~{tf**ussb;vpxK63vsg({30u;M&Xe%C=ogw(*~V)W}1xNeoFrXH*UTN literal 0 HcmV?d00001 diff --git a/test/metaevent.jl b/test/metaevent.jl index 5ccba2f..97e45a8 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -31,4 +31,12 @@ @test_throws errtype MIDI.readsysexevent(Int(input[1]), IOBuffer(input[2:length(input)])) end end + + @testset "SequencerSpecificEvent" begin + midi = load("SequencerSpecific.mid") + length(getnotes(midi.tracks[1], midi.tpq)) > 0 + + sse = MIDI.SequencerSpecificEvent(0, 0x7f, [0x11, 0x21, 0x53, 0x1F]) + @test sse.ssdata == [0x11, 0x21, 0x53, 0x1F] + end end From e34be0822b08296821dd72f940fe7d2e7564a2a6 Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Wed, 17 Jul 2024 17:27:33 +0800 Subject: [PATCH 2/6] add test --- test/metaevent.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/metaevent.jl b/test/metaevent.jl index 97e45a8..c4c00da 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -34,7 +34,7 @@ @testset "SequencerSpecificEvent" begin midi = load("SequencerSpecific.mid") - length(getnotes(midi.tracks[1], midi.tpq)) > 0 + @test length(getnotes(midi.tracks[1], midi.tpq)) > 0 sse = MIDI.SequencerSpecificEvent(0, 0x7f, [0x11, 0x21, 0x53, 0x1F]) @test sse.ssdata == [0x11, 0x21, 0x53, 0x1F] From 00d31d9627debd60112da4991322eb1a67debd28 Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Fri, 19 Jul 2024 02:38:52 +0800 Subject: [PATCH 3/6] update tests --- Project.toml | 4 ++-- test/SequencerSpecific.mid | Bin 2846 -> 36 bytes test/metaevent.jl | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) mode change 100755 => 100644 test/SequencerSpecific.mid diff --git a/Project.toml b/Project.toml index ba1a274..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" @@ -9,7 +9,7 @@ IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e" [compat] FileIO = "1" -IterTools = "1.10.0" +IterTools = "1.8.0" julia = "1" [extras] diff --git a/test/SequencerSpecific.mid b/test/SequencerSpecific.mid old mode 100755 new mode 100644 index 93e5a4a930f44a2f4d0353ef2aedc9e32f6fd6f9..cdda7f38132d558ff5c3f65497d88187a48b7d4e GIT binary patch delta 22 dcmbOyrZPc9fPs(Ue?6OXF&6_1Bg21v1^_+W1rh)N literal 2846 zcmX|DO^@To5iRX#c9k^`T!b(PL;+}kaD;`{*2+qTJtCA-Wk!60~wja9%Mj4 z27wSOfPg3&G`X;YBnX&mZutlN3I0jG`M7zl-S{w=W`9(@s(STGuU6X)5k1CV>+HK% zt3Upp=z|WuJ?s4G5BuNk@4wp6_nn!oi2h1Hw7&ldmXBK0a(|%rYmey1HJ|@~eMa=> z4))E{GqTL~yQTf`{`Ogm_{Z&*^#J4MMu(mlKkt@b^6B!|t>rU1$NKHM-G1Z(-ItGm z_ib_ZEH|p9W|>+kuRglDHv9&zGMq$ZArG8mU~5goSojq)j%dVE01bo;ij($hN?v| zF<7V|S8`>m2v6abLK&93Vq&oLWCScQ7J0z3G&U#IsF)akB(F3V)Nc5~t0lP&lispt z)k<2-Uc(RCs~JE^FFESSwCXXniv*C$prC_%WwWeohD{mB8HE`{`O z_f$Ga;p24Y(%eBs%blF7f(*4>xf-Y&B(Yp5>Vj6FDisV;XCOQ(T`g4M$lquMPd#~w zf>f%Q!Vch1Y&gP$(pJCJJ%s4XnU}^IVDD41l9&srUndB!pb@%+1JoWXpi`ff!0pKZ zX2>tb6_^RqgTT~QpS=OA9T~hC6bw&qP`aIbUgG9|kf=D|rvcMlJxuy))ob{tCRa|4 z5SJo!hlGH1U(ss;a2$JTcEFLxv=tLyNj<_>PrzboE2S+(8vyExC{?dCG);Sg791NR zAe3&48Fupy)8*nKEbuY^_ZjL;Zx9`c0pL_4s8=YCEs z#_LR$dx0Dz_Zha~*%9$_zNjpob_7{-D%WBb&efWU=R`2GY`6t(ICXY?*YF1+KVV6E zCx&ho>n@fnL5d}1x%TnJLaOW)JZj1aHcLk?x>oS=AL}bE0XEP7+g-6d>0~;ipLGsFn+7c)e}-V>l|^TEx8}flAuP zrGTT-gye|G*zRY)hSX`arFOA{D1GKK%%~?KV;8m3n})9fK67jJMf+t2eM6h@t>H?q z7Qx}=snWU!!+iv;Xe~aelz=uQlocn_fw(M>*nz_J5Q!27yMkyj5c#{ zhq>LHW=DCbMPvasxS|FN>3M0oh0m4Bj;set?zCiOd z;B%{<-wXiUt49(vcpUN#@ZZ&Q1bC@Hvn}qrhyd&cg+(q~{Bga)EvaOs{@!CQq4)^bYgZ=d`!X`^XA@T!7m9rRfp~x3r7TOC-z^GR3U# zs?SlOHcxc`QE-Gr@hC(M0rMIBtn1-*x8ZXGSJh%14o_XGQ=WEnWk|FZlWl&=%OP8m zoSbNc7SK!Z2RvHxWS!@w3)KQA`Z*bHbsC<+y7ueQRa+H&a`sSmYr)XT6g)CCbub;l z7NfxE2XvKdL~>+C7+Nr_()n`aI~i3QnZj6!!tLM*DR7w4*p~`00r{W%c!ue0-^@r}*bVyz{+53Z z)8BAy=th_~{tf**ussb;vpxK63vsg({30u;M&Xe%C=ogw(*~V)W}1xNeoFrXH*UTN diff --git a/test/metaevent.jl b/test/metaevent.jl index c4c00da..5b24624 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -34,8 +34,7 @@ @testset "SequencerSpecificEvent" begin midi = load("SequencerSpecific.mid") - @test length(getnotes(midi.tracks[1], midi.tpq)) > 0 - + sse = MIDI.SequencerSpecificEvent(0, 0x7f, [0x11, 0x21, 0x53, 0x1F]) @test sse.ssdata == [0x11, 0x21, 0x53, 0x1F] end From 2a2b8da108013a7b4c62f6f47474fb723f4a73bf Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Fri, 19 Jul 2024 18:11:09 +0800 Subject: [PATCH 4/6] implement `empty!(::MIDITrack)` --- CHANGELOG.md | 3 ++- src/miditrack.jl | 4 ++++ test/metaevent.jl | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe45f0..8effa86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ 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 event type `SequencerSpecificEvent`. +* New meta event type `SequencerSpecificEvent`. +* Implement `empty!(::MIDITrack)`. # v2.6.0 * New functions `metric_time`. * New functions `duration_metric_time`. diff --git a/src/miditrack.jl b/src/miditrack.jl index 82ef160..a2eefb4 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. + +The `empty!` function can be used to clear all events in the `MIDITrack`. """ 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 +empty!(t::MIDITrack) = empty!(t.events) + function readtrack(f::IO) diff --git a/test/metaevent.jl b/test/metaevent.jl index 5b24624..3f4b9d1 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -34,6 +34,9 @@ @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] From 8a15674879628a3ff8ff93772d39f70f81d2a211 Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Fri, 19 Jul 2024 18:29:06 +0800 Subject: [PATCH 5/6] add isempty for MIDITrack --- CHANGELOG.md | 2 +- src/miditrack.jl | 6 +++--- test/metaevent.jl | 8 ++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8effa86..f353f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ 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 `empty!(::MIDITrack)`. +* Implement `Base.empty!(::MIDITrack)` and `Base.isempty(t::MIDITrack)`. # v2.6.0 * New functions `metric_time`. * New functions `duration_metric_time`. diff --git a/src/miditrack.jl b/src/miditrack.jl index a2eefb4..77342d6 100644 --- a/src/miditrack.jl +++ b/src/miditrack.jl @@ -8,7 +8,7 @@ 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. -The `empty!` function can be used to clear all events in the `MIDITrack`. +`MIDITrack` implements the `isempty`` and `empty!` functions. """ mutable struct MIDITrack events::Vector{TrackEvent} @@ -23,8 +23,8 @@ function Base.show(io::IO, t::MIDITrack) print(io, "$(L)-event MIDITrack: $M MIDI, $T Meta, $X Sysex") end -empty!(t::MIDITrack) = empty!(t.events) - +Base.empty!(t::MIDITrack) = empty!(t.events) +Base.isempty(t::MIDITrack)::Bool = isempty(t.events) function readtrack(f::IO) diff --git a/test/metaevent.jl b/test/metaevent.jl index 3f4b9d1..b77f4ec 100644 --- a/test/metaevent.jl +++ b/test/metaevent.jl @@ -41,4 +41,12 @@ 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 From a2663ca592608664b552c76815e1f9c760420b8e Mon Sep 17 00:00:00 2001 From: Nero Blackstone Date: Fri, 19 Jul 2024 18:35:43 +0800 Subject: [PATCH 6/6] fix typo --- src/miditrack.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miditrack.jl b/src/miditrack.jl index 77342d6..6909a6a 100644 --- a/src/miditrack.jl +++ b/src/miditrack.jl @@ -8,7 +8,7 @@ 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. +`MIDITrack` implements the `isempty` and `empty!` functions. """ mutable struct MIDITrack events::Vector{TrackEvent}