cwSvgMidi.h/cpp : piano_score_to_svg().
This commit is contained in:
parent
7e462e2754
commit
06d985f271
312
cwSvgMidi.cpp
312
cwSvgMidi.cpp
@ -3,6 +3,7 @@
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwObject.h"
|
||||
#include "cwText.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwMidi.h"
|
||||
#include "cwMidiFile.h"
|
||||
@ -11,19 +12,21 @@
|
||||
#include "cwMidiState.h"
|
||||
#include "cwSvgMidi.h"
|
||||
|
||||
#define PEDAL_COUNT 3
|
||||
#define SUST_PEDAL_IDX 0
|
||||
#define SOST_PEDAL_IDX 1
|
||||
#define SOFT_PEDAL_IDX 2
|
||||
|
||||
#define PIX_PER_SEC 100.0
|
||||
#define NOTE_HEIGHT 15.0
|
||||
#define TIME_GRID_SECS 5.0
|
||||
#define PITCH_LABEL_INTERVAL_SECS 10
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace svg_midi
|
||||
{
|
||||
|
||||
enum {
|
||||
kBarTypeId,
|
||||
kSectionTypeId
|
||||
};
|
||||
|
||||
rc_t _write_svg_rect( svg::handle_t svgH, double secs0, double secs1, double y, const char* label, unsigned color )
|
||||
{
|
||||
rc_t rc;
|
||||
@ -77,8 +80,23 @@ namespace cw
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t _write_svg_line( svg::handle_t svgH, double sec0, double y0, double sec1, double y1, unsigned color )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
void _write_note_rect( svg::handle_t svgH, const midi_state::event_t* e0, const midi_state::event_t* e1, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
if((rc = line(svgH, sec0*PIX_PER_SEC, y0, sec1*PIX_PER_SEC, y1, "stroke", color, "rgb")) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error writing SVG line.");
|
||||
goto errLabel;
|
||||
|
||||
}
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
const midi_state::event_t* _write_note_rect( svg::handle_t svgH, const midi_state::event_t* e0, const midi_state::event_t* e1, const midi_state::event_t* t0, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
{
|
||||
cwAssert( e0!=nullptr && e1!=nullptr && e0->msg != nullptr && e1->msg !=nullptr);
|
||||
|
||||
@ -88,17 +106,23 @@ namespace cw
|
||||
|
||||
|
||||
unsigned muid = e0->msg->u.midi.uid;
|
||||
if( t0!=nullptr && e0->secs - t0->secs < PITCH_LABEL_INTERVAL_SECS )
|
||||
snprintf(label,labelCharN,"%i",muid);
|
||||
else
|
||||
{
|
||||
snprintf(label,labelCharN,"%s - %i",sciPitch,muid);
|
||||
t0 = e1;
|
||||
}
|
||||
|
||||
double y = -1.0 * (e0->msg->u.midi.d0 - minMidiPitch) + (maxMidiPitch - minMidiPitch);
|
||||
|
||||
_write_svg_rect( svgH, e0->secs, e1->secs, y, label, 0xafafaf );
|
||||
|
||||
return t0;
|
||||
}
|
||||
|
||||
void _write_sound_line( svg::handle_t svgH, const midi_state::event_t* e0, const midi_state::event_t* e1, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
{
|
||||
|
||||
cwAssert( e0!=nullptr && e1!=nullptr && e0->msg != nullptr && e1->msg !=nullptr);
|
||||
|
||||
double y = -1.0 * (e0->msg->u.midi.d0 - minMidiPitch) + (maxMidiPitch - minMidiPitch);
|
||||
@ -106,15 +130,32 @@ namespace cw
|
||||
_write_svg_horz_line( svgH, e0->secs, e1->secs, y, 0xafafaf );
|
||||
}
|
||||
|
||||
void _write_marker( svg::handle_t svgH, const midi_state::event_t* e, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
{
|
||||
unsigned color = e->msg->u.marker.typeId == kBarTypeId ? 0x0000ff : 0xff0000;
|
||||
_write_svg_vert_line( svgH, e->secs, color, minMidiPitch, maxMidiPitch );
|
||||
unsigned labelCharN = 127;
|
||||
char label[labelCharN+1];
|
||||
snprintf(label,labelCharN,"%i",e->msg->u.marker.value);
|
||||
|
||||
svg::text( svgH, e->secs*PIX_PER_SEC, -20, label );
|
||||
|
||||
}
|
||||
|
||||
void _write_svg_ch_note( svg::handle_t svgH, const midi_state::event_t* e0, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
{
|
||||
const midi_state::event_t* e = e0;
|
||||
const midi_state::event_t* n0 = nullptr;
|
||||
const midi_state::event_t* s0 = nullptr;
|
||||
const midi_state::event_t* t0 = nullptr;
|
||||
|
||||
for(; e!=nullptr; e=e->link)
|
||||
{
|
||||
if( cwIsFlag(e->flags,midi_state::kMarkerEvtFl) )
|
||||
{
|
||||
_write_marker( svgH, e, minMidiPitch, maxMidiPitch );
|
||||
}
|
||||
|
||||
if( cwIsFlag(e->flags,midi_state::kNoteOffFl) )
|
||||
{
|
||||
if( n0 == nullptr )
|
||||
@ -123,7 +164,7 @@ namespace cw
|
||||
}
|
||||
else
|
||||
{
|
||||
_write_note_rect( svgH, n0, e, minMidiPitch, maxMidiPitch );
|
||||
t0 = _write_note_rect( svgH, n0, e, t0, minMidiPitch, maxMidiPitch );
|
||||
}
|
||||
|
||||
n0 = nullptr;
|
||||
@ -135,7 +176,7 @@ namespace cw
|
||||
if( n0 != nullptr )
|
||||
{
|
||||
// TODO: check for reattack flag
|
||||
_write_note_rect( svgH, n0, e, minMidiPitch, maxMidiPitch );
|
||||
t0 = _write_note_rect( svgH, n0, e, t0, minMidiPitch, maxMidiPitch );
|
||||
}
|
||||
|
||||
n0 = e;
|
||||
@ -167,70 +208,17 @@ namespace cw
|
||||
s0 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
rc_t _write_svg_pedal( svg_midi_t* p, svg::handle_t svgH, const graphic_evt_t* ge, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
const char* label = nullptr;
|
||||
unsigned pedal_id = 0;
|
||||
unsigned color;
|
||||
|
||||
switch( ge->beg_evt->d0 & 0xf0 )
|
||||
{
|
||||
case midi::kSustainCtlMdId:
|
||||
label = "damp";
|
||||
pedal_id = 0;
|
||||
color = 0xf4a460;
|
||||
break;
|
||||
|
||||
case midi::kSostenutoCtlMdId:
|
||||
label = "sost";
|
||||
pedal_id = 1;
|
||||
color = 0x7fffd4;
|
||||
break;
|
||||
|
||||
case midi::kSoftPedalCtlMdId:
|
||||
label = "soft";
|
||||
pedal_id = 2;
|
||||
color = 0x98fb98;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
double y = (maxMidiPitch - minMidiPitch) + 1 + pedal_id;
|
||||
|
||||
if((rc = _write_svg_rect( p, svgH, ge, y, label, color )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error writing SVG pedal rect.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = _write_svg_line( p, svgH, ge->beg_evt->time, color, minMidiPitch, maxMidiPitch )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error writing SVG pedal begin line.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = _write_svg_line( p, svgH, ge->end_evt->time, color, minMidiPitch, maxMidiPitch )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error writing SVG pedal end line.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
*/
|
||||
|
||||
void _write_svg_ch_pedal( svg::handle_t svgH, const midi_state::event_t* e, unsigned pedal_idx, unsigned minMidiPitch, unsigned maxMidiPitch )
|
||||
void _write_svg_ch_pedal( svg::handle_t svgH, const midi_state::event_t* e, unsigned pedal_idx, unsigned minMidiPitch, unsigned maxMidiPitch, unsigned pedalCnt )
|
||||
{
|
||||
const midi_state::event_t* e0 = nullptr;
|
||||
const midi_state::event_t* e1 = nullptr;
|
||||
unsigned color = 0;
|
||||
const char* label = nullptr;
|
||||
switch( midi_state::pedal_index_to_midi_ctl_id(pedal_idx) )
|
||||
unsigned midiCtlId = midi_state::pedal_index_to_midi_ctl_id(pedal_idx);
|
||||
|
||||
switch( midiCtlId )
|
||||
{
|
||||
case midi::kSustainCtlMdId:
|
||||
label = "damp";
|
||||
@ -252,9 +240,9 @@ namespace cw
|
||||
|
||||
for(; e!=nullptr; e=e->link)
|
||||
{
|
||||
if( cwIsFlag(e->flags,midi_state::kNoChangeFl) )
|
||||
continue;
|
||||
|
||||
if( !cwIsFlag(e->flags,midi_state::kNoChangeFl) )
|
||||
{
|
||||
if( cwIsFlag(e->flags,midi_state::kDownPedalFl) )
|
||||
{
|
||||
if( e0 != nullptr )
|
||||
@ -276,37 +264,109 @@ namespace cw
|
||||
else
|
||||
{
|
||||
|
||||
// two consecutve pedal ups - this shouldn't be possible
|
||||
double y = (maxMidiPitch - minMidiPitch) + 1 + pedal_idx;
|
||||
|
||||
_write_svg_rect( svgH, e0->secs, e->secs, y, label, color );
|
||||
|
||||
if( midiCtlId == midi::kSustainCtlMdId )
|
||||
_write_svg_vert_line( svgH, e->secs, color, minMidiPitch, maxMidiPitch );
|
||||
|
||||
e0 = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( e1 != nullptr )
|
||||
{
|
||||
unsigned yOffs = ((maxMidiPitch - minMidiPitch) + pedalCnt) * NOTE_HEIGHT;
|
||||
_write_svg_line( svgH, e1->secs, yOffs + e1->msg->u.midi.d1, e->secs, yOffs + e->msg->u.midi.d1, color );
|
||||
}
|
||||
e1 = e;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rc_t _load_from_piano_score( midi_state::handle_t msH, const char* piano_score_fname )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
score::handle_t scH;
|
||||
unsigned n = 0;
|
||||
|
||||
if((rc = score::create( scH, piano_score_fname )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"The piano score load failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
const score::event_t* e = base_event(scH);
|
||||
|
||||
for(; e!=nullptr; e=e->link)
|
||||
{
|
||||
uint8_t ch = 0;
|
||||
|
||||
if( e->bar != 0 )
|
||||
if((rc = setMarker(msH, e->sec, e->uid, ch, kBarTypeId, e->bar )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error setting bar marker.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( e->section != 0 )
|
||||
if((rc = setMarker(msH, e->sec, e->uid, ch, kSectionTypeId, e->section )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error setting section marker.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( e->status != 0 )
|
||||
{
|
||||
if( e->status < 255 && e->d0 < 128 && e->d1 < 128 )
|
||||
{
|
||||
uint8_t status = (uint8_t)e->status & 0xf0;
|
||||
uint8_t ch = (uint8_t)e->status & 0x0f;
|
||||
uint8_t d0 = (uint8_t)e->d0;
|
||||
uint8_t d1 = (uint8_t)e->d1;
|
||||
|
||||
//printf("%i : %i %i : %i %x %i %i\n", n, e->uid, e->loc, ch, status, d0, d1 );
|
||||
|
||||
if((rc = setMidiMsg(msH, e->sec, e->uid, ch, status, d0, d1 ) ) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error on MIDI event insertion.");
|
||||
goto errLabel;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
destroy(scH);
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cw::rc_t cw::svg_midi::write( const char* fname, midi_state::handle_t msH )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
uint8_t minMidiPitch = midi::kMidiNoteCnt;
|
||||
uint8_t maxMidiPitch = 0;
|
||||
const midi_state::event_t* evt = nullptr;
|
||||
|
||||
unsigned pedal_cnt = midi_state::pedal_count( msH );
|
||||
double minSec = 0.0;
|
||||
double maxSec = 0.0;
|
||||
|
||||
const midi_state::event_t* evt = nullptr;
|
||||
svg::handle_t svgH;
|
||||
|
||||
|
||||
get_note_extents( msH, minMidiPitch, maxMidiPitch, minSec, maxSec );
|
||||
|
||||
printf("pitch - min:%i max:%i sec - min:%f max:%f\n",minMidiPitch,maxMidiPitch,minSec,maxSec);
|
||||
|
||||
// create the SVG file object
|
||||
if((rc = svg::create(svgH)) != kOkRC )
|
||||
{
|
||||
@ -314,6 +374,10 @@ cw::rc_t cw::svg_midi::write( const char* fname, midi_state::handle_t msH )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// create the time grid
|
||||
for(double sec = 0.0; sec<=maxSec; sec+=TIME_GRID_SECS)
|
||||
_write_svg_vert_line(svgH, sec, 0xefefef, minMidiPitch, maxMidiPitch );
|
||||
|
||||
// create the note graphics
|
||||
for(uint8_t i=0; i<midi::kMidiChCnt; ++i)
|
||||
for(uint8_t j=0; j<midi::kMidiNoteCnt; ++j)
|
||||
@ -324,7 +388,7 @@ cw::rc_t cw::svg_midi::write( const char* fname, midi_state::handle_t msH )
|
||||
for(uint8_t i=0; i<midi::kMidiChCnt; ++i)
|
||||
for(uint8_t j=0; j<midi_state::pedal_count(msH); ++j)
|
||||
if((evt = pedal_event_list(msH,i,j)) != nullptr )
|
||||
_write_svg_ch_pedal(svgH, evt, j, minMidiPitch, maxMidiPitch );
|
||||
_write_svg_ch_pedal(svgH, evt, j, minMidiPitch, maxMidiPitch, pedal_cnt );
|
||||
|
||||
|
||||
// write the SVG file
|
||||
@ -339,49 +403,6 @@ cw::rc_t cw::svg_midi::write( const char* fname, midi_state::handle_t msH )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
cw::rc_t cw::svg_midi::load_from_piano_score( handle_t h, const char* piano_score_fname )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
svg_midi_t* p = _handleToPtr(h);
|
||||
score::handle_t scH;
|
||||
|
||||
|
||||
if((rc = score::create( scH, piano_score_fname )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"The piano score load failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned evtN = event_count(scH);
|
||||
const score::event_t* evtA = base_event(scH);
|
||||
time::spec_t timestamp;
|
||||
|
||||
for(unsigned i=0; i<evtN; ++i)
|
||||
{
|
||||
const score::event_t* e = evtA + i;
|
||||
|
||||
time::secondsToSpec(timestamp,e->sec);
|
||||
|
||||
if( e->bar != 0 )
|
||||
_setEvent(p, kBarTypeId, e->bar, timestamp, i, 0,0,0 );
|
||||
|
||||
if( e->section != 0 )
|
||||
_setEvent(p, kSectionTypeId, e->section, timestamp, i, 0,0,0 );
|
||||
|
||||
if( e->status != 0 )
|
||||
_setEvent(p, kMidiTypeId, 0, timestamp, i, 0,0,0 );
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
destroy(scH);
|
||||
|
||||
return rc;
|
||||
}
|
||||
*/
|
||||
|
||||
cw::rc_t cw::svg_midi::midi_to_svg_file( const char* midi_fname, const char* out_fname, const object_t* midi_state_args )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
@ -389,7 +410,7 @@ cw::rc_t cw::svg_midi::midi_to_svg_file( const char* midi_fname, const char* out
|
||||
|
||||
|
||||
// create the MIDI state object - with caching turned on
|
||||
if((rc = midi_state::create( msH, nullptr, nullptr, true, midi_state_args )) != kOkRC )
|
||||
if((rc = midi_state::create( msH, nullptr, nullptr, midi_state_args )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error creating the midi_state object.");
|
||||
goto errLabel;
|
||||
@ -413,48 +434,51 @@ cw::rc_t cw::svg_midi::midi_to_svg_file( const char* midi_fname, const char* out
|
||||
destroy(msH);
|
||||
return rc;
|
||||
}
|
||||
/*
|
||||
cw::rc_t cw::svg_midi::piano_score_to_svg_file( const char* piano_score_fname, const char* out_fname, unsigned midiMsgCacheCnt, unsigned pedalUpMidiValue )
|
||||
|
||||
cw::rc_t cw::svg_midi::piano_score_to_svg_file( const char* piano_score_fname, const char* out_fname, const object_t* midi_state_args )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
handle_t h;
|
||||
midi_state::handle_t msH;
|
||||
|
||||
// create the SVG-MIDI object
|
||||
if((rc = create(h,midiMsgCacheCnt,pedalUpMidiValue)) != kOkRC )
|
||||
|
||||
// create the MIDI state object - with caching turned on
|
||||
if((rc = midi_state::create( msH, nullptr, nullptr, midi_state_args )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error creating the SVG-MIDI object.");
|
||||
rc = cwLogError(rc,"Error creating the midi_state object.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// load the MIDI file msg events into the svg-midi cache
|
||||
if((rc = load_from_piano_score(h, piano_score_fname)) != kOkRC )
|
||||
// load the MIDI file
|
||||
if((rc = _load_from_piano_score( msH, piano_score_fname)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error loading the piano score file.");
|
||||
rc = cwLogError(rc,"Error loading midi file into midi_state object.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// write the SVG file
|
||||
if((rc = write(h,out_fname)) != kOkRC )
|
||||
if((rc = write(out_fname,msH)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Error write the SVG-MIDI file.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
errLabel:
|
||||
destroy(h);
|
||||
|
||||
destroy(msH);
|
||||
return rc;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
cw::rc_t cw::svg_midi::test_midi_file( const object_t* cfg )
|
||||
{
|
||||
rc_t rc;
|
||||
const char* midi_fname = nullptr;
|
||||
const char* src_file_type = nullptr;
|
||||
const char* src_fname = nullptr;
|
||||
const char* out_fname = nullptr;
|
||||
const object_t* midi_state_args = nullptr;
|
||||
|
||||
if((rc = cfg->getv( "midi_fname", midi_fname,
|
||||
if((rc = cfg->getv(
|
||||
"src_file_type", src_file_type,
|
||||
"src_fname", src_fname,
|
||||
"out_fname", out_fname,
|
||||
"midi_state_args",midi_state_args)) != kOkRC )
|
||||
{
|
||||
@ -462,7 +486,23 @@ cw::rc_t cw::svg_midi::test_midi_file( const object_t* cfg )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
rc = midi_to_svg_file( midi_fname, out_fname, midi_state_args );
|
||||
if( textCompare( src_file_type, "midi" ) == 0 )
|
||||
{
|
||||
rc = midi_to_svg_file( src_fname, out_fname, midi_state_args );
|
||||
}
|
||||
else
|
||||
if( textCompare( src_file_type, "piano_score" ) == 0 )
|
||||
{
|
||||
rc = piano_score_to_svg_file( src_fname, out_fname, midi_state_args );
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"Invalid file type:'%s'.",cwStringNullGuard(src_file_type));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( rc != kOkRC )
|
||||
cwLogError(rc,"The SVG file create failed.");
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
|
@ -8,7 +8,7 @@ namespace cw
|
||||
rc_t write( const char* fname, midi_state::handle_t msH );
|
||||
|
||||
rc_t midi_to_svg_file( const char* midi_fname, const char* out_fname, const object_t* midi_state_args );
|
||||
//rc_t piano_score_to_svg_file( const char* piano_score_fname, const char* out_fname, const object_t* cfg );
|
||||
rc_t piano_score_to_svg_file( const char* piano_score_fname, const char* out_fname, const object_t* midi_state_args );
|
||||
|
||||
rc_t test_midi_file( const object_t* cfg );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user