From 2d88e689b530ea7adf373680468aea895116d319 Mon Sep 17 00:00:00 2001 From: kevin Date: Sun, 20 Aug 2023 17:14:52 -0400 Subject: [PATCH] cwDynRefTbl.h/cpp : Initial commit. --- cwDynRefTbl.cpp | 165 ++++++++++++++++++++++++++++++++++++++++++++++++ cwDynRefTbl.h | 37 +++++++++++ 2 files changed, 202 insertions(+) create mode 100644 cwDynRefTbl.cpp create mode 100644 cwDynRefTbl.h diff --git a/cwDynRefTbl.cpp b/cwDynRefTbl.cpp new file mode 100644 index 0000000..c34b211 --- /dev/null +++ b/cwDynRefTbl.cpp @@ -0,0 +1,165 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwMidi.h" +#include "cwDynRefTbl.h" + +namespace cw +{ + namespace dyn_ref_tbl + { + typedef struct dyn_ref_tbl_str + { + dyn_ref_t* dynRefA; + unsigned dynRefN; + + } dyn_ref_tbl_t; + + dyn_ref_tbl_t* _handleToPtr( handle_t h ) + { return handleToPtr(h); } + + rc_t _destroy( dyn_ref_tbl_t* p ) + { + rc_t rc = kOkRC; + + auto relse = [](dyn_ref_t& x) { mem::release(x.marker); }; + + std::for_each(p->dynRefA, p->dynRefA+p->dynRefN, relse ); + mem::release(p->dynRefA); + mem::release(p); + return rc; + } + + rc_t _parse_cfg( dyn_ref_tbl_t* p, const object_t* cfg ) + { + rc_t rc = kOkRC; + + // parse the dynamics ref. array + p->dynRefN = cfg->child_count(); + + if( p->dynRefN == 0 ) + cwLogWarning("The dynamic reference array cfg. is empty."); + else + { + p->dynRefA = mem::allocZ(p->dynRefN); + + for(unsigned i=0; idynRefN; ++i) + { + const object_t* r = cfg->child_ele(i); + const char* marker = nullptr; + + if((rc = r->getv("mark", marker, + "level", p->dynRefA[i].level, + "vel", p->dynRefA[i].velocity)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"Error parsing the dynamics reference array."); + goto errLabel; + } + + p->dynRefA[i].marker = mem::duplStr(marker); + } + } + + + errLabel: + + return rc; + } + } +} + +cw::rc_t cw::dyn_ref_tbl::create( handle_t& hRef, const object_t* cfg ) +{ + rc_t rc; + if((rc = destroy(hRef)) != kOkRC ) + return rc; + + dyn_ref_tbl_t* p = mem::allocZ(); + + if((rc = _parse_cfg( p, cfg )) != kOkRC ) + { + rc = cwLogError(rc,"Dynamics reference table parse failed."); + goto errLabel; + } + + hRef.set(p); + + errLabel: + + return rc; +} + +cw::rc_t cw::dyn_ref_tbl::destroy( handle_t& hRef ) +{ + rc_t rc = kOkRC; + + if(!hRef.isValid()) + return rc; + + dyn_ref_tbl_t* p = _handleToPtr(hRef); + + if((rc = _destroy(p)) != kOkRC ) + return rc; + + hRef.clear(); + + return rc; +} + +const char* cw::dyn_ref_tbl::level_to_marker( handle_t h, unsigned level ) +{ + dyn_ref_tbl_t* p = _handleToPtr(h); + for(unsigned i=0; idynRefN; ++i) + if( p->dynRefA[i].level ) + return p->dynRefA[i].marker; + return nullptr; +} + +unsigned cw::dyn_ref_tbl::marker_to_level( handle_t h, const char* marker ) +{ + dyn_ref_tbl_t* p = _handleToPtr(h); + for(unsigned i=0; idynRefN; ++i) + if( textIsEqual(p->dynRefA[i].marker,marker) ) + return p->dynRefA[i].level; + return kInvalidIdx; +} + +cw::midi::byte_t cw::dyn_ref_tbl::level_to_velocity( handle_t h , unsigned level ) +{ + dyn_ref_tbl_t* p = _handleToPtr(h); + for(unsigned i=0; idynRefN; ++i) + if( p->dynRefA[i].level == level ) + return p->dynRefA[i].velocity; + return midi::kInvalidMidiByte; +} + +unsigned cw::dyn_ref_tbl::velocity_to_level( handle_t h, midi::byte_t vel ) +{ + dyn_ref_tbl_t* p = _handleToPtr(h); + + for(unsigned i=0; idynRefN; ++i) + if( p->dynRefA[i].velocity > vel ) + { + midi::byte_t d0 = p->dynRefA[i].velocity - vel; + + midi::byte_t d1 = i>0 ? (vel - p->dynRefA[i-1].velocity) : d0; + + unsigned j = d0 <= d1 ? i : i-1; + + return p->dynRefA[j].level; + } + + return p->dynRefA[ p->dynRefN-1 ].velocity; +} + +void cw::dyn_ref_tbl::report( handle_t h ) +{ + dyn_ref_tbl_t* p = _handleToPtr(h); + + auto rpt = [](dyn_ref_t& x) { printf("%2i %3i %s\n",x.level,x.velocity,x.marker); }; + + std::for_each(p->dynRefA,p->dynRefA+p->dynRefN, rpt ); +} diff --git a/cwDynRefTbl.h b/cwDynRefTbl.h new file mode 100644 index 0000000..f78bb43 --- /dev/null +++ b/cwDynRefTbl.h @@ -0,0 +1,37 @@ +#ifndef cwDynRefTbl_h +#define cwDynRefTbl_h + +namespace cw +{ + namespace dyn_ref_tbl + { + typedef struct dyn_ref_str + { + char* marker; // text marker (e.g. p,mf_m,mf,mf_p, ff, ...) + unsigned level; // level as a numeric id - generally in range 0-19 (0=silent, 1=lowest audible dynamic) + uint8_t velocity; // level as a MIDI velocity + } dyn_ref_t; + + typedef handle handle_t; + + + // Parse object like: [ { mark:<> level:<>, vel:<> } ] + rc_t create( handle_t& hRef, const object_t* cfg ); + rc_t destroy( handle_t& hRef ); + + const char* level_to_marker( handle_t h, unsigned level ); + + // Returns kInvalidIdx on error. + unsigned marker_to_level( handle_t h, const char* marker ); + + // Return midi::kInvalidMidiByte on error + midi::byte_t level_to_velocity( handle_t h, unsigned level ); + + // MIDI velocity to nearest dynamic level + unsigned velocity_to_level( handle_t h, midi::byte_t vel ); + + void report( handle_t h ); + } +} + +#endif