cwScoreParse.h/cpp : Converted location variables names to consistently use oLocId and eLocId.

Added: event_t.bpm_rval, use of 'show_warnings_fl', more validity checks.
This commit is contained in:
kevin 2023-09-12 17:53:35 -04:00
parent 7c076fbef1
commit b9f497e1ec
2 changed files with 145 additions and 62 deletions

View File

@ -190,8 +190,12 @@ namespace cw
{ {
rc_t rc; rc_t rc;
if((rc = getv(csvH,"bpm",e->bpm)) != kOkRC ) if((rc = getv(csvH,
"bpm",e->bpm,
"rval",e->bpm_rval )) != kOkRC )
{
rc = cwLogError(rc,"BPM row parse failed."); rc = cwLogError(rc,"BPM row parse failed.");
}
return rc; return rc;
} }
@ -268,10 +272,10 @@ namespace cw
const char* dynLabel = nullptr; const char* dynLabel = nullptr;
const char* evenLabel = nullptr; const char* evenLabel = nullptr;
const char* tempoLabel = nullptr; const char* tempoLabel = nullptr;
const char* oloc = nullptr; const char* oLocId = nullptr;
if((rc = getv(csvH, if((rc = getv(csvH,
"oloc", oloc, "oloc", oLocId,
"rval", e->rval, "rval", e->rval,
"dots", e->dotCnt, "dots", e->dotCnt,
"sci_pitch",sciPitch, "sci_pitch",sciPitch,
@ -290,10 +294,10 @@ namespace cw
goto errLabel; goto errLabel;
} }
if( textLength(oloc) > 0 ) if( textLength(oLocId) > 0 )
if((rc = string_to_number(oloc,e->oloc)) != kOkRC ) if((rc = string_to_number(oLocId,e->oLocId)) != kOkRC )
{ {
rc = cwLogError(rc,"Error converting oloc (%s) to number.",oloc); rc = cwLogError(rc,"Error converting oLocId (%s) to number.",oLocId);
goto errLabel; goto errLabel;
} }
@ -397,6 +401,8 @@ namespace cw
section_t* cur_section = nullptr; section_t* cur_section = nullptr;
unsigned cur_bar_numb = 1; unsigned cur_bar_numb = 1;
unsigned bar_evt_idx = 0; unsigned bar_evt_idx = 0;
unsigned bpm = 0;
double bpm_rval = 0;
unsigned barPitchCntV[ midi::kMidiNoteCnt ]; unsigned barPitchCntV[ midi::kMidiNoteCnt ];
vop::zero(barPitchCntV,midi::kMidiNoteCnt); vop::zero(barPitchCntV,midi::kMidiNoteCnt);
@ -412,14 +418,12 @@ namespace cw
event_t* e = p->eventA + p->eventN; event_t* e = p->eventA + p->eventN;
e->oloc = kInvalidIdx; e->oLocId = kInvalidIdx;
if((rc = getv(csvH, if((rc = getv(csvH,
"opcode",opcodeLabel, "opcode",opcodeLabel,
"index", e->csvId,
"voice", e->voice, "voice", e->voice,
"loc", e->loc, "eloc", e->eLocId,
"loctn", e->loctn,
"tick", e->tick, "tick", e->tick,
"sec", e->sec )) != kOkRC ) "sec", e->sec )) != kOkRC )
{ {
@ -429,6 +433,8 @@ namespace cw
e->csvRowNumb = cur_line_index(csvH) + 1; e->csvRowNumb = cur_line_index(csvH) + 1;
e->opId = opcode_label_to_id(opcodeLabel); e->opId = opcode_label_to_id(opcodeLabel);
e->index = p->eventN;
e->dynLevel = kInvalidIdx;
switch( e->opId ) switch( e->opId )
{ {
@ -453,7 +459,32 @@ namespace cw
break; break;
case kBpmTId: case kBpmTId:
rc = _parse_bpm_row(p,csvH, e ); if((rc = _parse_bpm_row(p,csvH, e )) == kOkRC )
{
// if the cur BPM has not yet been set then go backward setting
// all events prior to this to the initial BPM
if( bpm == 0 && e->bpm != 0 )
std::for_each(p->eventA,e,[e](auto& x){ x.bpm = e->bpm; x.bpm_rval=e->bpm_rval; });
// if the parsed BPM is invalid ...
if( e->bpm == 0 || e->bpm_rval==0 )
{
e->bpm = bpm; // ... then ignore it
e->bpm_rval = bpm_rval;
}
else
{
bpm = e->bpm; // ... otherwise make it the current BPM
bpm_rval = e->bpm_rval;
}
// Be sure that all events on this location have the same BPM
for(event_t* e0 = e - 1; e0>=p->eventA && e0->eLocId==e->eLocId; --e0)
{
e0->bpm = e->bpm;
e0->bpm_rval = e->bpm_rval;
}
}
break; break;
case kNoteOnTId: case kNoteOnTId:
@ -462,6 +493,7 @@ namespace cw
e->barPitchIdx = barPitchCntV[e->d0]; e->barPitchIdx = barPitchCntV[e->d0];
unsigned hash = form_hash(e->opId,cur_bar_numb,e->d0,e->barPitchIdx); unsigned hash = form_hash(e->opId,cur_bar_numb,e->d0,e->barPitchIdx);
if( _hash_to_event(p,hash) != nullptr ) if( _hash_to_event(p,hash) != nullptr )
{ {
rc = cwLogError(kInvalidStateRC,"The event hash '%x' is is duplicated.",hash); rc = cwLogError(kInvalidStateRC,"The event hash '%x' is is duplicated.",hash);
@ -502,6 +534,8 @@ namespace cw
e->section = cur_section; e->section = cur_section;
e->barNumb = cur_bar_numb; e->barNumb = cur_bar_numb;
e->barEvtIdx = bar_evt_idx++; e->barEvtIdx = bar_evt_idx++;
e->bpm = bpm;
e->bpm_rval = bpm_rval;
p->eventN += 1; p->eventN += 1;
} }
@ -527,7 +561,7 @@ namespace cw
rc_t _parse_csv( score_parse_t* p, const char* fname ) rc_t _parse_csv( score_parse_t* p, const char* fname )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const char* titleA[] = { "opcode","meas","index","voice","loc","loctn","oloc","tick","sec", const char* titleA[] = { "opcode","meas","index","voice","loc","eloc","oloc","tick","sec",
"dur","rval","dots","sci_pitch","dmark","dlevel","status","d0","d1", "dur","rval","dots","sci_pitch","dmark","dlevel","status","d0","d1",
"bar","section","bpm","grace","tie","onset","pedal","dyn","even","tempo" }; "bar","section","bpm","grace","tie","onset","pedal","dyn","even","tempo" };
@ -613,7 +647,7 @@ namespace cw
// then the set is complete // then the set is complete
// (this handles the case where there are multiple events // (this handles the case where there are multiple events
// on the same end set location) // on the same end set location)
if( endLoc != kInvalidIdx && (e->loctn > endLoc || ei==p->eventN-1) ) if( endLoc != kInvalidIdx && (e->eLocId > endLoc || ei==p->eventN-1) )
{ {
cur_set->eventA = mem::allocZ<event_t*>(cur_set->eventN); cur_set->eventA = mem::allocZ<event_t*>(cur_set->eventN);
setId += 1; setId += 1;
@ -633,7 +667,7 @@ namespace cw
cur_set->eventN += 1; cur_set->eventN += 1;
if( cwIsFlag(e->varA[vi].flags,kSetEndVarFl) ) if( cwIsFlag(e->varA[vi].flags,kSetEndVarFl) )
endLoc = e->loctn; endLoc = e->eLocId;
} }
} }
} }
@ -682,11 +716,11 @@ namespace cw
{ {
unsigned j; unsigned j;
for(j=0; j<loc_i; ++j) for(j=0; j<loc_i; ++j)
if( loc[j] == set->eventA[i]->loctn ) if( loc[j] == set->eventA[i]->eLocId )
break; break;
if( j == loc_i ) if( j == loc_i )
loc[ loc_i++ ] = set->eventA[i]->loctn; loc[ loc_i++ ] = set->eventA[i]->eLocId;
} }
} }
@ -733,7 +767,7 @@ namespace cw
} }
} }
void _fill_sections( score_parse_t* p ) void _fill_section_sets( score_parse_t* p )
{ {
// allocate memory to hold the set ptr arrays in each section // allocate memory to hold the set ptr arrays in each section
for(section_t* s = p->sectionL; s!=nullptr; s=s->link) for(section_t* s = p->sectionL; s!=nullptr; s=s->link)
@ -746,22 +780,39 @@ namespace cw
set->targetSection->setA[ set->sectionSetIdx ] = set; set->targetSection->setA[ set->sectionSetIdx ] = set;
// set the section beg/end events // set the section beg/end events
if( set->targetSection->begEvent == nullptr ) if( set->targetSection->begSetEvent == nullptr )
{ {
set->targetSection->begEvent = set->eventA[0]; set->targetSection->begSetEvent = set->eventA[0];
set->targetSection->endEvent = set->eventA[ set->eventN-1 ]; set->targetSection->endSetEvent = set->eventA[ set->eventN-1 ];
} }
else else
{ {
if( set->eventA[0]->sec < set->targetSection->begEvent->sec ) if( set->eventA[0]->sec < set->targetSection->begSetEvent->sec )
set->targetSection->begEvent = set->eventA[0]; set->targetSection->begSetEvent = set->eventA[0];
if( set->eventA[set->eventN-1]->sec > set->targetSection->endEvent->sec ) if( set->eventA[set->eventN-1]->sec > set->targetSection->endSetEvent->sec )
set->targetSection->endEvent = set->eventA[ set->eventN-1 ]; set->targetSection->endSetEvent = set->eventA[ set->eventN-1 ];
} }
} }
} }
rc_t _fill_section_beg_end_evt( score_parse_t* p )
{
rc_t rc = kOkRC;
for(unsigned i=0; i<p->eventN; ++i)
{
event_t* e = p->eventA + i;
assert( e->section != nullptr );
if( e->section->begEvent == nullptr || e->index < e->section->begEvent->index )
e->section->begEvent = e;
if( e->section->endEvent == nullptr || e->index > e->section->endEvent->index )
e->section->endEvent = e;
}
return rc;
}
bool _compare_sections(const section_t* sec0, const section_t* sec1) bool _compare_sections(const section_t* sec0, const section_t* sec1)
{ {
return sec0->csvRowNumb < sec1->csvRowNumb; return sec0->csvRowNumb < sec1->csvRowNumb;
@ -808,7 +859,7 @@ namespace cw
mem::release(secA); mem::release(secA);
} }
rc_t _validate_sections( score_parse_t* p ) rc_t _validate_sections( score_parse_t* p, bool show_warnings_fl )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
@ -818,10 +869,11 @@ namespace cw
{ {
if( s->setN == 0 ) if( s->setN == 0 )
{ {
if( show_warnings_fl )
cwLogWarning("The section '%s' does not have any sets assigned to it.",cwStringNullGuard(s->label)); cwLogWarning("The section '%s' does not have any sets assigned to it.",cwStringNullGuard(s->label));
} }
else else
if( s->begEvent == nullptr || s->endEvent == nullptr ) if( s->begSetEvent == nullptr || s->endSetEvent == nullptr )
{ {
rc = cwLogError(kInvalidStateRC,"The section '%s' does not beg/end events.",cwStringNullGuard(s->label)); rc = cwLogError(kInvalidStateRC,"The section '%s' does not beg/end events.",cwStringNullGuard(s->label));
continue; continue;
@ -836,6 +888,31 @@ namespace cw
s0 = s; s0 = s;
} }
// verify that there are no event gaps between the sections
if( p->sectionL != nullptr and p->sectionL->link != nullptr )
{
s0 = p->sectionL;
for(section_t* s=s0->link; s!=nullptr; s=s->link)
{
if( s0->endEvent == nullptr )
rc = cwLogError(kInvalidStateRC,"The section '%s' does not have an end event.",cwStringNullGuard(s0->label));
else
{
if( s->begEvent == nullptr )
rc = cwLogError(kInvalidStateRC,"The section '%s' does not have a begin event.",cwStringNullGuard(s->label));
else
{
if( s0->endEvent->index+1 != s->begEvent->index )
rc = cwLogError(kInvalidStateRC,"The sections '%s' and '%s' do not begin/end on consecutive events.",cwStringNullGuard(s0->label),cwStringNullGuard(s->label));
}
}
s0 = s;
}
}
if( rc != kOkRC ) if( rc != kOkRC )
rc = cwLogError(rc,"Section validation failed."); rc = cwLogError(rc,"Section validation failed.");
return rc; return rc;
@ -908,6 +985,11 @@ unsigned cw::score_parse::dyn_ref_label_to_level( handle_t h, const char* label
return marker_to_level( p->dynRefH, label ); return marker_to_level( p->dynRefH, label );
} }
unsigned cw::score_parse::dyn_ref_vel_to_level( handle_t h, uint8_t vel )
{
score_parse_t* p = _handleToPtr(h);
return velocity_to_level(p->dynRefH,vel);
}
unsigned cw::score_parse::form_hash( unsigned op_id, unsigned bar, uint8_t midi_pitch, unsigned barPitchIdx ) unsigned cw::score_parse::form_hash( unsigned op_id, unsigned bar, uint8_t midi_pitch, unsigned barPitchIdx )
{ {
@ -932,7 +1014,7 @@ void cw::score_parse::parse_hash( unsigned hash, unsigned& op_idRef, unsi
} }
cw::rc_t cw::score_parse::create( handle_t& hRef, const char* fname, double srate, dyn_ref_tbl::handle_t dynRefH ) cw::rc_t cw::score_parse::create( handle_t& hRef, const char* fname, double srate, dyn_ref_tbl::handle_t dynRefH, bool show_warnings_fl )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
score_parse_t* p = nullptr; score_parse_t* p = nullptr;
@ -960,16 +1042,15 @@ cw::rc_t cw::score_parse::create( handle_t& hRef, const char* fname, double srat
_fill_target_sections(p); _fill_target_sections(p);
_fill_sections(p); _fill_section_sets(p);
_sort_sections(p); _sort_sections(p);
if((rc = _validate_sections(p)) != kOkRC ) _fill_section_beg_end_evt(p);
if((rc = _validate_sections(p,show_warnings_fl)) != kOkRC )
goto errLabel; goto errLabel;
hRef.set(p); hRef.set(p);
errLabel: errLabel:
@ -1056,10 +1137,8 @@ void cw::score_parse::report( handle_t h )
const char* blank = " "; const char* blank = " ";
const unsigned flN = 6; const unsigned flN = 6;
printf("row op section bpm b_rval bar bei voc tick sec rval dot eloc oloc flags bpm stat d0 d1 spich hash \n");
printf("---- --- ------- --- ------ ----- --- --- ---- ------- ------ --- ----- ----- ----- --- ---- ---- --- ----- --------\n");
printf("row op section bar bei voc tick sec rval dot lo c lctn oloc flags bpm stat d0 d1 spich hash \n");
printf("---- --- ------- ----- --- --- ---- ------- ------ --- ----- ----- ----- ----- --- ---- ---- --- ----- --------\n");
for(unsigned i=0; i<p->eventN; ++i) for(unsigned i=0; i<p->eventN; ++i)
{ {
@ -1076,11 +1155,13 @@ void cw::score_parse::report( handle_t h )
if( cwIsFlag(e->flags,kTieEndFl)) { flag_str[fli++] = 'T'; } if( cwIsFlag(e->flags,kTieEndFl)) { flag_str[fli++] = 'T'; }
if( cwIsFlag(e->flags,kOnsetFl)) { flag_str[fli++] = 'o'; } if( cwIsFlag(e->flags,kOnsetFl)) { flag_str[fli++] = 'o'; }
printf("%4i %3s %2s%4s %2s%3i %3i %3i %4i %7.3f %6.3f %3i %5i %5i %5i %5s %3i 0x%02x 0x%02x %3i %5s", printf("%4i %3s %2s%4s %3i %6.4f %2s%3i %3i %3i %4i %7.3f %6.3f %3i %5i %5i %5s %3i 0x%02x 0x%02x %3i %5s",
e->csvRowNumb, e->csvRowNumb,
opcode_id_to_label(e->opId), opcode_id_to_label(e->opId),
secLabel, secLabel,
e->section == nullptr || e->section->label==nullptr ? "" : e->section->label , e->section == nullptr || e->section->label==nullptr ? "" : e->section->label ,
e->bpm,
e->bpm_rval,
barLabel, barLabel,
e->barNumb, e->barNumb,
e->barEvtIdx, e->barEvtIdx,
@ -1089,9 +1170,8 @@ void cw::score_parse::report( handle_t h )
e->sec, e->sec,
e->rval, e->rval,
e->dotCnt, e->dotCnt,
e->loc, e->eLocId,
e->loctn, e->oLocId,
e->oloc,
flag_str, flag_str,
e->bpm, e->bpm,
e->status, e->status,

View File

@ -47,26 +47,28 @@ namespace cw
struct event_str; struct event_str;
typedef struct section_str typedef struct section_str
{ {
char* label; char* label; // This sections label
unsigned csvRowNumb; // score CSV row number where this section starts unsigned csvRowNumb; // score CSV row number where this section starts
unsigned setN; unsigned setN; // Count of elements in setA[]
struct set_str** setA; struct set_str** setA; // setA[setN] Array of pointers to sets that are applied to this section.
struct event_str* begEvent; struct event_str* begEvent; // first event in this section
struct event_str* endEvent; struct event_str* endEvent; // last event in this section
struct section_str* link; struct event_str* begSetEvent; // first set event in this section
struct event_str* endSetEvent; // last set event in this section
struct section_str* link; // p->sectionL links
} section_t; } section_t;
struct event_str; struct event_str;
typedef struct set_str typedef struct set_str
{ {
unsigned id; unsigned id; // Unique id for this set
unsigned varTypeId; unsigned varTypeId; // Type of measurement to perform on this set.
unsigned eventN; unsigned eventN; // Count of elements in eventA[]
struct event_str** eventA; struct event_str** eventA; // eventA[eventN] Pointers to all events in this set.
section_t* targetSection; section_t* targetSection; // Section this set will be applied to.
unsigned sectionSetIdx; // index of this set in the section unsigned sectionSetIdx; // Index of this set in the targetSection->setA[].
struct set_str* link; struct set_str* link; // p->setL link
} set_t; } set_t;
typedef struct event_var_str typedef struct event_var_str
@ -81,7 +83,7 @@ namespace cw
{ {
unsigned csvRowNumb; // CSV row number this event was derived from unsigned csvRowNumb; // CSV row number this event was derived from
unsigned opId; // event type unsigned opId; // event type
unsigned csvId; // CSV 'index' column unsigned index; // index of this recod in event_array()
section_t* section; // section that this event belongs to section_t* section; // section that this event belongs to
unsigned barNumb; // unsigned barNumb; //
unsigned barEvtIdx; // index of this event in this bar unsigned barEvtIdx; // index of this event in this bar
@ -93,10 +95,10 @@ namespace cw
unsigned dotCnt; unsigned dotCnt;
unsigned dynLevel; // dynamic level based on marker unsigned dynLevel; // dynamic level based on marker
unsigned hash; // [ op_id:4 bar:12 pitch:8 bar_pitch_n:8 ] unsigned hash; // [ op_id:4 bar:12 pitch:8 bar_pitch_n:8 ]
unsigned loc; unsigned eLocId; // event location id (includes all events, oloc includes just note-ons)
unsigned loctn; unsigned oLocId; // onset location id (onset loc id's used by sfScore)
unsigned oloc;
unsigned bpm; unsigned bpm;
double bpm_rval;
unsigned flags; unsigned flags;
midi::byte_t status; midi::byte_t status;
midi::byte_t d0; midi::byte_t d0;
@ -118,11 +120,12 @@ namespace cw
const char* dyn_ref_level_to_label( handle_t h, unsigned vel ); const char* dyn_ref_level_to_label( handle_t h, unsigned vel );
unsigned dyn_ref_label_to_level( handle_t h, const char* label ); unsigned dyn_ref_label_to_level( handle_t h, const char* label );
unsigned dyn_ref_vel_to_level( handle_t h, uint8_t vel );
unsigned form_hash( unsigned op_id, unsigned bar, uint8_t midi_pitch, unsigned barPitchIdx ); unsigned form_hash( unsigned op_id, unsigned bar, uint8_t midi_pitch, unsigned barPitchIdx );
void parse_hash( unsigned hash, unsigned& op_idRef, unsigned& barRef, uint8_t& midi_pitchRef, unsigned& barPitchIdxRef ); void parse_hash( unsigned hash, unsigned& op_idRef, unsigned& barRef, uint8_t& midi_pitchRef, unsigned& barPitchIdxRef );
rc_t create( handle_t& hRef, const char* fname, double srate, dyn_ref_tbl::handle_t dynRefH ); rc_t create( handle_t& hRef, const char* fname, double srate, dyn_ref_tbl::handle_t dynRefH, bool show_warnings_fl=false );
rc_t destroy( handle_t& hRef ); rc_t destroy( handle_t& hRef );
double sample_rate( handle_t h ); double sample_rate( handle_t h );