From 53dfdbc2a5103e6e4b8f46bcf8c5012f8535ef1f Mon Sep 17 00:00:00 2001 From: kevin Date: Sun, 20 Mar 2022 10:18:16 -0400 Subject: [PATCH] cwPianoScore.cpp: Added CSV reader. --- cwPianoScore.cpp | 198 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 1 deletion(-) diff --git a/cwPianoScore.cpp b/cwPianoScore.cpp index dc9f111..f757f59 100644 --- a/cwPianoScore.cpp +++ b/cwPianoScore.cpp @@ -6,6 +6,7 @@ #include "cwPianoScore.h" #include "cwMidi.h" #include "cwTime.h" +#include "cwFile.h" namespace cw { @@ -38,6 +39,189 @@ namespace cw return rc; } + unsigned _scan_to_end_of_field( const char* lineBuf, unsigned buf_idx, unsigned bufCharCnt ) + { + for(; buf_idx < bufCharCnt; ++buf_idx ) + { + if( lineBuf[buf_idx] == '"' ) + { + for(++buf_idx; buf_idx < bufCharCnt; ++buf_idx) + if( lineBuf[buf_idx] == '"' ) + break; + } + + if( lineBuf[buf_idx] == ',') + break; + } + + return buf_idx; + } + + + rc_t _parse_csv_double( const char* lineBuf, unsigned bfi, unsigned efi, double &valueRef ) + { + errno = 0; + valueRef = strtod(lineBuf+bfi,nullptr); + if( errno != 0 ) + return cwLogError(kOpFailRC,"CSV String to number conversion failed."); + + return kOkRC; + } + + rc_t _parse_csv_unsigned( const char* lineBuf, unsigned bfi, unsigned efi, unsigned &valueRef ) + { + rc_t rc; + double v; + if((rc = _parse_csv_double(lineBuf,bfi,efi,v)) == kOkRC ) + valueRef = (unsigned)v; + return rc; + } + + rc_t _parse_csv_line( score_t* p, event_t* e, char* line_buf, unsigned lineBufCharCnt ) + { + enum + { + kMeas_FIdx, + kIndex_FIdx, + kVoice_FIdx, + kLoc_FIdx, + kTick_FIdx, + kSec_FIdx, + kDur_FIdx, + kRval_FIdx, + kSPitch_FIdx, + kDMark_FIdx, + kDLevel_FIdx, + kStatus_FIdx, + kD0_FIdx, + kD1_FIdx, + kBar_FIdx, + kSection_FIdx, + kBpm_FIdx, + kGrace_FIdx, + kPedal_FIdx, + kMax_FIdx + }; + + rc_t rc = kOkRC; + unsigned bfi = 0; + unsigned efi = 0; + unsigned field_idx = 0; + + + for(field_idx=0; field_idx != kMax_FIdx; ++field_idx) + { + if((efi = _scan_to_end_of_field(line_buf,efi,lineBufCharCnt)) == kInvalidIdx ) + { + rc = cwLogError( rc, "End of field scan failed"); + goto errLabel; + } + + + if( bfi != efi ) + { + switch( field_idx ) + { + case kLoc_FIdx: + rc = _parse_csv_unsigned( line_buf, bfi, efi, e->loc ); + break; + + case kSec_FIdx: + rc = _parse_csv_double( line_buf, bfi, efi, e->sec ); + break; + + case kStatus_FIdx: + rc = _parse_csv_unsigned( line_buf, bfi, efi, e->status ); + break; + + case kD0_FIdx: + rc = _parse_csv_unsigned( line_buf, bfi, efi, e->d0 ); + break; + + case kD1_FIdx: + rc = _parse_csv_unsigned( line_buf, bfi, efi, e->d1 ); + break; + + default: + break; + } + } + + bfi = efi + 1; + efi = efi + 1; + + } + + errLabel: + + return rc; + } + + + rc_t _parse_csv( score_t* p, const char* fn ) + { + rc_t rc; + file::handle_t fH; + unsigned line_count = 0; + char* lineBufPtr = nullptr; + unsigned lineBufCharCnt = 0; + + if((rc = file::open( fH, fn, file::kReadFl )) != kOkRC ) + { + rc = cwLogError( rc, "Piano score file open failed on '%s'.",cwStringNullGuard(fn)); + goto errLabel; + } + + if((rc = file::lineCount(fH,&line_count)) != kOkRC ) + { + rc = cwLogError( rc, "Line count query failed on '%s'.",cwStringNullGuard(fn)); + goto errLabel; + } + + + for(unsigned line=0; line 0 ) // skip column title line + { + event_t* e = mem::allocZ(); + + if((rc = getLineAuto( fH, &lineBufPtr, &lineBufCharCnt )) != kOkRC ) + { + rc = cwLogError( rc, "Line read failed on '%s' line number '%i'.",cwStringNullGuard(fn),line+1); + goto errLabel; + } + + if((rc = _parse_csv_line( p, e, lineBufPtr, lineBufCharCnt )) != kOkRC ) + { + rc = cwLogError( rc, "Line parse failed on '%s' line number '%i'.",cwStringNullGuard(fn),line+1); + goto errLabel; + } + + // assign the UID + e->uid = line; + + // link the event into the event list + if( p->end != nullptr ) + p->end->link = e; + else + p->base = e; + + p->end = e; + + // track the max 'loc' id + if( e->loc > p->maxLocId ) + p->maxLocId = e->loc; + + } + + + + errLabel: + mem::release(lineBufPtr); + file::close(fH); + + return rc; + } + rc_t _parse_event_list( score_t* p, const object_t* cfg ) { rc_t rc; @@ -136,11 +320,13 @@ cw::rc_t cw::score::create( handle_t& hRef, const char* fn ) { rc_t rc; object_t* cfg = nullptr; + score_t* p = nullptr; if((rc = destroy(hRef)) != kOkRC ) return rc; // parse the cfg file + /* if((rc = objectFromFile( fn, cfg )) != kOkRC ) { rc = cwLogError(rc,"Score parse failed on file: '%s'.", fn); @@ -148,11 +334,21 @@ cw::rc_t cw::score::create( handle_t& hRef, const char* fn ) } rc = create(hRef,cfg); + */ + + p = mem::allocZ< score_t >(); + + rc = _parse_csv(p,fn); + + hRef.set(p); - errLabel: + //errLabel: if( cfg != nullptr ) cfg->free(); + + if( rc != kOkRC ) + destroy(hRef); return rc; }