Browse Source

midi region export: only create midi notes on track 1 if only exporting region (not track or project)

cairo_optimizations
Alexandros Theodotou 3 years ago
parent
commit
3192a71575
Signed by: alex
GPG Key ID: 022EAE42313D70F3
  1. 13
      inc/audio/midi_region.h
  2. 4
      meson.build
  3. 189
      src/audio/midi_region.c
  4. 4
      src/audio/port.c
  5. 6
      src/audio/track.c
  6. 2
      src/audio/track_lane.c
  7. 2
      src/audio/tracklist.c
  8. BIN
      tests/1_empty_track_1_track_with_data.mid
  9. BIN
      tests/1_track_with_data.mid
  10. 97
      tests/actions/create_tracks.c
  11. 1
      tests/integration/midi_file.c
  12. 1
      tests/meson.build

13
inc/audio/midi_region.h

@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
#ifndef __AUDIO_MIDI_REGION_H__
#define __AUDIO_MIDI_REGION_H__
#include <stdbool.h>
#include <stdint.h>
typedef struct Track Track;
@ -194,13 +195,17 @@ midi_region_remove_all_midi_notes ( @@ -194,13 +195,17 @@ midi_region_remove_all_midi_notes (
* MIDI file as it would be played inside Zrythm.
* If this is 0, only the original region (from
* true start to true end) is exported.
* @param use_track_pos Whether to use the track
* position in the MIDI data. The track will be
* set to 1 if false.
*/
void
midi_region_write_to_midi_file (
ZRegion * self,
MIDI_FILE * mf,
const int add_region_start,
const int export_full);
ZRegion * self,
MIDI_FILE * mf,
const int add_region_start,
bool export_full,
bool use_track_pos);
/**
* Exports the ZRegion to a specified MIDI file.

4
meson.build

@ -157,14 +157,14 @@ cc = meson.get_compiler ('c') @@ -157,14 +157,14 @@ cc = meson.get_compiler ('c')
find_program ('sed', required: true)
find_program ('gettext', required: true)
dot_bin = find_program ('dot', required: false)
have_helm = false
helm_bundle = 'N/A'
if get_option ('tests')
lv2ls_bin = find_program ('lv2ls', required: false)
lv2info_bin = find_program (
'lv2info', required: false)
get_lv2_bundle_uri_bin = find_program (
'tools/get_lv2_bundle_uri.sh')
have_helm = false
helm_bundle = 'not found'
if lv2ls_bin.found () and lv2info_bin.found ()
lv2ls_res = run_command (
lv2ls_bin, check: true).stdout ()

189
src/audio/midi_region.c

@ -335,8 +335,10 @@ midi_region_new_from_midi_file ( @@ -335,8 +335,10 @@ midi_region_new_from_midi_file (
int idx_inside_lane,
int idx)
{
ZRegion * self =
calloc (1, sizeof (MidiRegion));
g_message (
"%s: reading from %s...", __func__, abs_path);
ZRegion * self = object_new (ZRegion);
self->id.type = REGION_TYPE_MIDI;
@ -344,7 +346,7 @@ midi_region_new_from_midi_file ( @@ -344,7 +346,7 @@ midi_region_new_from_midi_file (
midiFileOpen (abs_path);
g_return_val_if_fail (mf, NULL);
g_message ("reading region from midi file...");
bool print_details = false;
char str[128];
int ev;
@ -373,7 +375,8 @@ midi_region_new_from_midi_file ( @@ -373,7 +375,8 @@ midi_region_new_from_midi_file (
if (i != idx)
continue;
g_message("MIDI Track %d", i);
g_message (
"%s: reading MIDI Track %d", __func__, i);
while(midiReadGetNextMessage (mf, i, &msg))
{
/* convert time to zrythm time */
@ -381,7 +384,11 @@ midi_region_new_from_midi_file ( @@ -381,7 +384,11 @@ midi_region_new_from_midi_file (
((double) msg.dwAbsPos * transport_ppqn) /
ppqn;
position_from_ticks (&pos, ticks);
g_message("dwAbsPos: %d ", msg.dwAbsPos);
if (print_details)
{
g_message (
"dwAbsPos: %d ", msg.dwAbsPos);
}
position_print (&pos);
if (ZRYTHM_HAVE_UI &&
@ -404,17 +411,23 @@ midi_region_new_from_midi_file ( @@ -404,17 +411,23 @@ midi_region_new_from_midi_file (
ev = msg.iType;
}
if (muGetMIDIMsgName (str, ev))
g_message("MIDI msg name: %s", str);
if (muGetMIDIMsgName (str, ev) &&
print_details)
{
g_message("MIDI msg name: %s", str);
}
switch(ev)
{
case msgNoteOff:
g_message (
"Note off at %d "
"[ch %d pitch %d]",
msg.dwAbsPos,
msg.MsgData.NoteOff.iChannel,
msg.MsgData.NoteOff.iNote);
if (print_details)
{
g_message (
"Note off at %d "
"[ch %d pitch %d]",
msg.dwAbsPos,
msg.MsgData.NoteOff.iChannel,
msg.MsgData.NoteOff.iNote);
}
mn =
midi_region_pop_unended_note (
self, msg.MsgData.NoteOff.iNote);
@ -432,13 +445,16 @@ midi_region_new_from_midi_file ( @@ -432,13 +445,16 @@ midi_region_new_from_midi_file (
}
break;
case msgNoteOn:
g_message (
"Note on at %d "
"[ch %d pitch %d vel %d]",
msg.dwAbsPos,
msg.MsgData.NoteOn.iChannel,
msg.MsgData.NoteOn.iNote,
msg.MsgData.NoteOn.iVolume);
if (print_details)
{
g_message (
"Note on at %d "
"[ch %d pitch %d vel %d]",
msg.dwAbsPos,
msg.MsgData.NoteOn.iChannel,
msg.MsgData.NoteOn.iNote,
msg.MsgData.NoteOn.iVolume);
}
midi_region_start_unended_note (
self, &pos, NULL,
msg.MsgData.NoteOn.iNote,
@ -448,76 +464,106 @@ midi_region_new_from_midi_file ( @@ -448,76 +464,106 @@ midi_region_new_from_midi_file (
muGetNameFromNote (
str,
msg.MsgData.NoteKeyPressure.iNote);
g_message (
"(%.2d) %s %d",
msg.MsgData.NoteKeyPressure.
iChannel,
str,
msg.MsgData.NoteKeyPressure.
iPressure);
if (print_details)
{
g_message (
"(%.2d) %s %d",
msg.MsgData.NoteKeyPressure.
iChannel,
str,
msg.MsgData.NoteKeyPressure.
iPressure);
}
break;
case msgSetParameter:
muGetControlName (
str,
msg.MsgData.NoteParameter.iControl);
g_message (
"(%.2d) %s -> %d",
msg.MsgData.NoteParameter.iChannel,
str,
msg.MsgData.NoteParameter.iParam);
if (print_details)
{
g_message (
"(%.2d) %s -> %d",
msg.MsgData.NoteParameter.iChannel,
str,
msg.MsgData.NoteParameter.iParam);
}
break;
case msgSetProgram:
muGetInstrumentName (
str,
msg.MsgData.ChangeProgram.iProgram);
g_message (
"(%.2d) %s",
msg.MsgData.ChangeProgram.iChannel,
str);
if (print_details)
{
g_message (
"(%.2d) %s",
msg.MsgData.ChangeProgram.iChannel,
str);
}
break;
case msgChangePressure:
muGetControlName (
str,
msg.MsgData.ChangePressure.
iPressure);
g_message (
"(%.2d) %s",
msg.MsgData.ChangePressure.iChannel,
str);
if (print_details)
{
g_message (
"(%.2d) %s",
msg.MsgData.ChangePressure.iChannel,
str);
}
break;
case msgSetPitchWheel:
g_message (
"(%.2d) %d",
msg.MsgData.PitchWheel.iChannel,
msg.MsgData.PitchWheel.iPitch);
if (print_details)
{
g_message (
"(%.2d) %d",
msg.MsgData.PitchWheel.iChannel,
msg.MsgData.PitchWheel.iPitch);
}
break;
case msgMetaEvent:
g_message ("---- meta events");
if (print_details)
{
g_message ("---- meta events");
}
switch(msg.MsgData.MetaEvent.iType)
{
case metaMIDIPort:
g_message (
"MIDI Port = %d",
msg.MsgData.MetaEvent.Data.
iMIDIPort);
if (print_details)
{
g_message (
"MIDI Port = %d",
msg.MsgData.MetaEvent.Data.
iMIDIPort);
}
break;
case metaSequenceNumber:
g_message (
"Sequence Number = %d",
msg.MsgData.MetaEvent.Data.
iSequenceNumber);
if (print_details)
{
g_message (
"Sequence Number = %d",
msg.MsgData.MetaEvent.Data.
iSequenceNumber);
}
break;
case metaTextEvent:
g_message (
"Text = '%s'",
msg.MsgData.MetaEvent.Data.Text.
pData);
if (print_details)
{
g_message (
"Text = '%s'",
msg.MsgData.MetaEvent.Data.Text.
pData);
}
break;
case metaCopyright:
g_message (
"Copyright = '%s'",
msg.MsgData.MetaEvent.Data.Text.
pData);
if (print_details)
{
g_message (
"Copyright = '%s'",
msg.MsgData.MetaEvent.Data.Text.
pData);
}
break;
case metaTrackName:
{
@ -633,7 +679,7 @@ midi_region_new_from_midi_file ( @@ -633,7 +679,7 @@ midi_region_new_from_midi_file (
{
/* Already done a hex dump */
}
else
else if (print_details)
{
char txt[600];
char tmp[100];
@ -659,6 +705,8 @@ midi_region_new_from_midi_file ( @@ -659,6 +705,8 @@ midi_region_new_from_midi_file (
midiReadFreeMessage(&msg);
midiFileClose(mf);
g_message ("%s: done", __func__);
return self;
}
@ -716,13 +764,17 @@ midi_region_start_unended_note ( @@ -716,13 +764,17 @@ midi_region_start_unended_note (
* MIDI file as it would be played inside Zrythm.
* If this is 0, only the original region (from
* true start to true end) is exported.
* @param use_track_pos Whether to use the track
* position in the MIDI data. The track will be
* set to 1 if false.
*/
void
midi_region_write_to_midi_file (
ZRegion * self,
MIDI_FILE * mf,
const int add_region_start,
const int export_full)
ZRegion * self,
MIDI_FILE * mf,
const int add_region_start,
bool export_full,
bool use_track_pos)
{
MidiEvents * events =
midi_region_get_as_events (
@ -742,7 +794,8 @@ midi_region_write_to_midi_file ( @@ -742,7 +794,8 @@ midi_region_write_to_midi_file (
ev->raw_buffer[1],
ev->raw_buffer[2] };
midiTrackAddRaw (
mf, track->pos, 3, tmp, 1,
mf, use_track_pos ? track->pos : 1, 3, tmp,
1,
i == 0 ?
(int) ev->time :
(int)
@ -798,7 +851,7 @@ midi_region_export_to_midi_file ( @@ -798,7 +851,7 @@ midi_region_export_to_midi_file (
TRANSPORT->ticks_per_beat));
midi_region_write_to_midi_file (
self, mf, 0, export_full);
self, mf, 0, export_full, false);
midiFileClose(mf);
}

4
src/audio/port.c

@ -134,7 +134,7 @@ port_init_loaded ( @@ -134,7 +134,7 @@ port_init_loaded (
break;
}
g_message ("%s: done", __func__);
/*g_message ("%s: done", __func__);*/
}
/**
@ -488,7 +488,7 @@ _port_new ( @@ -488,7 +488,7 @@ _port_new (
self->id.flow = FLOW_UNKNOWN;
self->id.label = g_strdup (label);
g_message ("%s: done (%p)", __func__, self);
/*g_message ("%s: done (%p)", __func__, self);*/
return self;
}

6
src/audio/track.c

@ -1809,9 +1809,9 @@ track_set_is_project ( @@ -1809,9 +1809,9 @@ track_set_is_project (
{
port = ports[i];
g_return_if_fail (IS_PORT (port));
g_message (
"%s: setting %s (%p) to %d",
__func__, port->id.label, port, is_project);
/*g_message (*/
/*"%s: setting %s (%p) to %d",*/
/*__func__, port->id.label, port, is_project);*/
port_set_is_project (port, is_project);
}
free (ports);

2
src/audio/track_lane.c

@ -312,7 +312,7 @@ track_lane_write_to_midi_file ( @@ -312,7 +312,7 @@ track_lane_write_to_midi_file (
{
region = self->regions[i];
midi_region_write_to_midi_file (
region, mf, 1, 1);
region, mf, 1, true, true);
}
}

2
src/audio/tracklist.c

@ -181,7 +181,7 @@ tracklist_insert_track ( @@ -181,7 +181,7 @@ tracklist_insert_track (
int recalc_graph)
{
g_message (
"%s: inserting %s at %d...",
"------------------------------------- %s: inserting %s at %d...",
__func__, track->name, pos);
track_set_name (track, track->name, 0);

BIN
tests/1_empty_track_1_track_with_data.mid

Binary file not shown.

BIN
tests/1_track_with_data.mid

Binary file not shown.

97
tests/actions/create_tracks.c

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
/*
* Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of Zrythm
*
* Zrythm is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zrythm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/
#include "actions/create_tracks_action.h"
#include "actions/undoable_action.h"
#include "audio/audio_region.h"
#include "audio/automation_region.h"
#include "audio/chord_region.h"
#include "audio/master_track.h"
#include "audio/midi_note.h"
#include "audio/region.h"
#include "project.h"
#include "utils/flags.h"
#include "zrythm.h"
#include "tests/helpers/project.h"
#include <glib.h>
static void
test_num_tracks_with_file (
const char * filepath,
const int num_tracks)
{
SupportedFile * file =
supported_file_new_from_path (filepath);
int num_tracks_before = TRACKLIST->num_tracks;
UndoableAction * ua =
create_tracks_action_new (
TRACK_TYPE_MIDI, NULL, file,
num_tracks_before, PLAYHEAD, 1);
undo_manager_perform (
UNDO_MANAGER, ua);
g_assert_cmpint (
TRACKLIST->num_tracks, ==,
num_tracks_before + num_tracks);
}
static void
test_create_from_midi_file (void)
{
char * midi_file;
/* TODO this should pass in the future */
#if 0
midi_file =
g_build_filename (
TESTS_SRCDIR,
"1_empty_track_1_track_with_data.mid",
NULL);
test_num_tracks_with_file (midi_file, 2);
g_free (midi_file);
#endif
midi_file =
g_build_filename (
TESTS_SRCDIR,
"1_track_with_data.mid",
NULL);
test_num_tracks_with_file (midi_file, 1);
g_free (midi_file);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
test_helper_zrythm_init ();
#define TEST_PREFIX "/actions/arranger_selections/"
g_test_add_func (
TEST_PREFIX "test create from midi file",
(GTestFunc) test_create_from_midi_file);
return g_test_run ();
}

1
tests/integration/midi_file.c

@ -157,4 +157,3 @@ main (int argc, char *argv[]) @@ -157,4 +157,3 @@ main (int argc, char *argv[])
return g_test_run ();
}

1
tests/meson.build

@ -53,6 +53,7 @@ if get_option ('tests') @@ -53,6 +53,7 @@ if get_option ('tests')
# 1: is parallel
tests = [
['actions/arranger_selections', true],
['actions/create_tracks', true],
['audio/automation_track', true],
['audio/curve', true],
['audio/midi', true],

Loading…
Cancel
Save