helgoboss / reaper-rs

Rust bindings for the REAPER C++ API
MIT License
78 stars 8 forks source link

Midi functions draft #66

Open Levitanus opened 1 year ago

Levitanus commented 1 year ago

I've just built an iterator, that returns arbitrary "generic" midi events with PPQ position and all flags unpacked.

Then the decision is needed what to do:

Levitanus commented 1 year ago

Example:

fn test_midi_events() {
    let rpr = Reaper::get().medium_reaper();
    let pr = reaper_medium::ProjectContext::CurrentProject;
    let track = rpr.get_track(pr, 2).unwrap();
    let item = get_track_items(track).expect("should be item")[0];
    unsafe {
        let take = rpr.get_active_take(item).expect("should be take");
        assert_true(
            rpr.take_is_midi(&take),
            "Take is MIDI",
            "Take should be MIDI",
        );
        let events = rpr
            .midi_get_all_events_iter(take, 500)
            .expect("should be iterator");
        println!(
            "Events from iterator: {:#?}",
            events.collect::<Vec<SourceMidiEvent>>()
        );
    }
}

Out:

Events from iterator: [
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            240.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            144,
            60,
            96,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            480.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            128,
            60,
            0,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            720.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            144,
            62,
            96,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            960.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            128,
            62,
            0,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            1200.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            144,
            60,
            103,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            1440.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            128,
            60,
            0,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            1680.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            144,
            62,
            96,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            1680.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            255,
            15,
            78,
            79,
            84,
            69,
            32,
            48,
            32,
            54,
            50,
            32,
            97,
            114,
            116,
            105,
            99,
            117,
            108,
            97,
            116,
            105,
            111,
            110,
            32,
            115,
            116,
            97,
            99,
            99,
            97,
            116,
            105,
            115,
            115,
            105,
            109,
            111,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            1920.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            128,
            62,
            0,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            2400.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: SlowStartEnd,
        message: [
            176,
            1,
            108,
        ],
    },
    SourceMidiEvent {
        position_in_ppq: PositionInPpq(
            3840.0,
        ),
        is_selected: false,
        is_muted: false,
        cc_shape_kind: Square,
        message: [
            176,
            123,
            0,
        ],
    },
]
Levitanus commented 1 year ago

Now, I'm pretty sure in iterators. And again thinking of adding original single-event functions, as additional tool for self-check, and because more complex iterators through raw midi lays out of medium-level tasks.

Considering the naming: I've thought at first to name the original functions as they are, and functions with iterators like *_iter. But it seemed not expressive and not very clear for me. And I didn't find anything better, than call original uncomfortable to use functions midi_set_all_evts_raw and midi_get_all_evts_raw. But, since, anywhere, there is almost no case, when someone would prefer raw function over iterator — I don't think it is a big problem.

Levitanus commented 1 year ago

OK. Now the idea looks fine for me. Please, check if you like this API and realization, and I'll finish other MIDI_* functions.

I've checked, that everything works OK with real REAPER, just need to fix this in reaper-rs integration test.