From f7283ffcca178f612efb6d61ff788c08e9c990c1 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:42:20 -0400 Subject: [PATCH 1/7] cwIo.cpp : Fixed error message and code formatting. No functional changes. --- cwIo.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cwIo.cpp b/cwIo.cpp index dc3d565..37e140b 100644 --- a/cwIo.cpp +++ b/cwIo.cpp @@ -1347,7 +1347,7 @@ namespace cw unsigned audioBufFlags = 0; if((rc = _audioDeviceParams( p, devIdx, inOutEnaFlags, ad, audioBufFlags )) != kOkRC ) - rc = cwLogError(rc,"Enable tone failed."); + rc = cwLogError(rc,"Audio device to buffer parameter translation failed."); else { bool enaFl = inOutEnaFlags & kEnableFl; @@ -2011,11 +2011,11 @@ namespace cw for(unsigned i=0; iaudioDevN; ++i) if( p->audioDevA[i].activeFl && p->audioDevA[i].meterFl ) - if((rc = _audioDeviceEnableMeter(p, p->audioDevA[i].devIdx, kEnableFl | kInFl | kOutFl )) != kOkRC ) - { - cwLogError(rc,"Audio enable on device '%s' failed.",p->audioDevA[i].label); - goto errLabel; - } + if((rc = _audioDeviceEnableMeter(p, p->audioDevA[i].devIdx, kEnableFl | kInFl | kOutFl )) != kOkRC ) + { + cwLogError(rc,"Audio enable on device '%s' failed.",p->audioDevA[i].label); + goto errLabel; + } errLabel: return rc; From 2d749cabeb92b3da78f32927fbeb300aab5749dc Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:46:13 -0400 Subject: [PATCH 2/7] cwAudioBuf.h/cpp : Added damping to meter calculation and create() arg. 'meterDampCoeff'. --- cwAudioBuf.cpp | 14 +++++++++----- cwAudioBuf.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cwAudioBuf.cpp b/cwAudioBuf.cpp index d229497..f6c2799 100644 --- a/cwAudioBuf.cpp +++ b/cwAudioBuf.cpp @@ -103,6 +103,8 @@ namespace cw sample_t* zeroBuf; // buffer of zeros unsigned zeroBufCnt; // max of all dspFrameCnt for all devices. + + float meter_damp_coeff; } audioBuf_t; inline audioBuf_t* _handleToPtr( handle_t h ) { return handleToPtr(h); } @@ -263,7 +265,7 @@ namespace cw } } -cw::rc_t cw::audio::buf::create( handle_t& hRef, unsigned devCnt, unsigned meterMs ) +cw::rc_t cw::audio::buf::create( handle_t& hRef, unsigned devCnt, unsigned meterMs, float meterDampCoeff ) { rc_t rc; @@ -274,7 +276,8 @@ cw::rc_t cw::audio::buf::create( handle_t& hRef, unsigned devCnt, unsigned meter p->devArray = mem::allocZ(devCnt ); p->devCnt = devCnt; - + p->meter_damp_coeff = meterDampCoeff; + hRef.set(p); setMeterMs(hRef,meterMs); @@ -422,11 +425,10 @@ cw::rc_t cw::audio::buf::update( sample_t* dp = cp->b + cp->ii; const sample_t* ep = dp + n0; - // update the meter if( cwIsFlag(cp->fl,kMeterFl) ) { - cp->m[cp->mi] = _cmApMeter(sp,pp->audioFramesCnt,pp->chCnt); + cp->m[cp->mi] = (1.0f - p->meter_damp_coeff) * cp->m[cp->mi] + p->meter_damp_coeff*_cmApMeter(sp,pp->audioFramesCnt,pp->chCnt); cp->mi = (cp->mi + 1) % cp->mn; } @@ -538,7 +540,9 @@ cw::rc_t cw::audio::buf::update( // update the meter if( cwIsFlag(cp->fl,kMeterFl) ) { - cp->m[cp->mi] = _cmApMeter(((sample_t*)pp->audioBytesPtr)+j,pp->audioFramesCnt,pp->chCnt); + //cp->m[cp->mi] = _cmApMeter(((sample_t*)pp->audioBytesPtr)+j,pp->audioFramesCnt,pp->chCnt); + cp->m[cp->mi] = (1.0f - p->meter_damp_coeff) * cp->m[cp->mi] + p->meter_damp_coeff*_cmApMeter(((sample_t*)pp->audioBytesPtr)+j,pp->audioFramesCnt,pp->chCnt); + cp->mi = (cp->mi + 1) % cp->mn; } diff --git a/cwAudioBuf.h b/cwAudioBuf.h index 48b7eea..273b508 100644 --- a/cwAudioBuf.h +++ b/cwAudioBuf.h @@ -66,7 +66,7 @@ namespace cw // Allocate and initialize an audio buffer. // devCnt - count of devices this buffer will handle. // meterMs - length of the meter buffers in milliseconds (automatically limit to the range:10 to 1000) - rc_t create( handle_t& hRef, unsigned devCnt, unsigned meterMs ); + rc_t create( handle_t& hRef, unsigned devCnt, unsigned meterMs, float meterDampCoeff=0.4 ); // Deallocate and release any resource held by an audio buffer allocated via initialize(). rc_t destroy( handle_t& hRef ); From 17aaa45edb063bc25db8d0add547d32074c9008b Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:47:39 -0400 Subject: [PATCH 3/7] cwIoMidiRecordPlay.cpp : Changed AM file version to -2 in _midi_write(). This is just a safety measure in case the format changed since the last time AM files were used. --- cwIoMidiRecordPlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwIoMidiRecordPlay.cpp b/cwIoMidiRecordPlay.cpp index 490670c..31b4e04 100644 --- a/cwIoMidiRecordPlay.cpp +++ b/cwIoMidiRecordPlay.cpp @@ -937,7 +937,7 @@ namespace cw file::handle_t fH; // NOTE: version must be a small negative number to differentiate from file version that // whose first word is the count of records in the file, rather than the version number - int version = -1; + int version = -2; if( p->iMsgArrayInIdx == 0 ) { From 6e8bc206a243d90731ca6ab7134e6382f20f1d51 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:49:19 -0400 Subject: [PATCH 4/7] cwIoAudioMidiApp.cpp : Added call to midiDeviceClearBuffer(). Added option audio device metering. --- cwIoAudioMidiApp.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 2 deletions(-) diff --git a/cwIoAudioMidiApp.cpp b/cwIoAudioMidiApp.cpp index 6ad4217..58788c9 100644 --- a/cwIoAudioMidiApp.cpp +++ b/cwIoAudioMidiApp.cpp @@ -47,7 +47,10 @@ namespace cw kSaveBtnId, kOpenBtnId, - kFnStringId + kFnStringId, + + kMeterPanelId, + kBaseAudioMeterId }; enum @@ -81,10 +84,21 @@ namespace cw { kPanelDivId, kSaveBtnId, "saveBtnId" }, { kPanelDivId, kOpenBtnId, "openBtnId" }, { kPanelDivId, kFnStringId, "filenameId" }, + + { kPanelDivId, kMeterPanelId, "meterPanelId" } }; unsigned mapN = sizeof(mapA)/sizeof(mapA[0]); + + const double kMeterMinVal = 0.0; + const double kMeterMaxVal = 100.0; + + typedef struct audio_meter_str + { + unsigned uuid; + char* title; + } audio_meter_t; typedef struct app_str { @@ -101,6 +115,13 @@ namespace cw const object_t* midi_play_record_cfg; + unsigned audioDevIdx; + unsigned audioInChCnt; + + bool activate_meters_fl; + audio_meter_t* meterA; + std::atomic meterSetupCompleteFl; + } app_t; rc_t _parseCfg(app_t* app, const object_t* cfg ) @@ -111,6 +132,7 @@ namespace cw "record_dir", app->record_dir, "record_folder", app->record_folder, "record_fn_ext", app->record_fn_ext, + "activate_meters_fl", app->activate_meters_fl, "midi_play_record", app->midi_play_record_cfg)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Audio MIDI app configuration parse failed."); @@ -136,6 +158,10 @@ namespace cw rc_t _free( app_t& app ) { + for(unsigned i=0; iioH ); + for(unsigned i=0; iioH,i) ) + { + app->audioDevIdx = i; + app->audioInChCnt = audioDeviceChannelCount(app->ioH,i,io::kInFl); + + + if((rc = audioDeviceEnableMeters(app->ioH, app->audioDevIdx, io::kInFl | io::kEnableFl )) != kOkRC ) + { + rc = cwLogError(rc,"Audio meter enable failed on device index:%i.",app->audioDevIdx); + goto errLabel; + } + + cwLogInfo("Active audio device index:%i in chs:%i\n",app->audioDevIdx,app->audioInChCnt); + + break; + } + + errLabel: + return rc; + + } + + rc_t _create_audio_meters( app_t* app ) + { + rc_t rc = kOkRC; + + unsigned meterPanelUuId = uiFindElementUuId( app->ioH, "meterPanelId" ); + + if( app->audioDevIdx == kInvalidIdx || app->audioInChCnt==0 ) + { + cwLogWarning("No meters created. No active input audio device was found."); + goto errLabel; + } + + app->meterA = mem::resizeZ(app->meterA,app->audioInChCnt ); + + for(unsigned i=0; iaudioInChCnt; ++i) + { + app->meterA[i].title = mem::printf(app->meterA[i].title,"%i",i); + + if((rc = uiCreateProg(app->ioH, app->meterA[i].uuid, meterPanelUuId, nullptr, kBaseAudioMeterId+i, 0, NULL, app->meterA[i].title, kMeterMinVal, kMeterMaxVal )) != kOkRC ) + { + cwLogError(rc,"Audio input meter create failed on channel index:%i.",i); + goto errLabel; + } + + } + + app->meterSetupCompleteFl.store(true); + + errLabel: + if(rc != kOkRC ) + cwLogError(rc,"Audio meter creation failed."); + + return rc; + } + + rc_t _on_audio_meters(app_t* app, const io::audio_group_dev_t* agd ) + { + rc_t rc = kOkRC; + if( app->activate_meters_fl && app->meterSetupCompleteFl.load() && cwIsFlag(agd->flags,io::kInFl) ) + { + unsigned n = std::min(app->audioInChCnt,agd->chCnt); + for(unsigned i=0; imeterA[i]) + 100.0 ); + if((rc = io::uiSendValue(app->ioH, app->meterA[i].uuid, db)) != kOkRC ) + { + rc = cwLogError(rc,"Audio meter update failed on channel index:%i.",i); + goto errLabel; + } + } + } + errLabel: + return rc; + } + + rc_t _onUiInit(app_t* app, const io::ui_msg_t& m ) { rc_t rc = kOkRC; + + if( app->activate_meters_fl) + if((rc = _get_active_audio_dev_and_ch_count(app)) == kOkRC ) + _create_audio_meters(app); return rc; } @@ -511,12 +624,15 @@ namespace cw break; case io::kMidiTId: + // Drop the MIDI messages that were processed on this call. + midiDeviceClearBuffer(app->ioH,m->u.midi->pkt->msgCnt); break; case io::kAudioTId: break; case io::kAudioMeterTId: + _on_audio_meters(app,m->u.audioGroupDev); break; case io::kSockTId: @@ -550,6 +666,10 @@ cw::rc_t cw::audio_midi_app::main( const object_t* cfg ) rc_t rc; app_t app = {}; + app.audioDevIdx = kInvalidIdx; + app.audioInChCnt = 0; + app.meterSetupCompleteFl.store(false); + // Parse the configuration if((rc = _parseCfg(&app,cfg)) != kOkRC ) goto errLabel; @@ -596,6 +716,8 @@ cw::rc_t cw::audio_midi_app::main( const object_t* cfg ) } errLabel: + destroy(app.mrpH); + destroy(app.arpH); _free(app); io::destroy(app.ioH); printf("Audio-MIDI Done.\n"); From 415f0ca955f2ac0535d2a66c2d88afa2fd494b4b Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:50:34 -0400 Subject: [PATCH 5/7] audio_midi/js/ui.js : Fixed ui_set_number_display() precision error and added use of precisionRound() --- html/audio_midi/js/ui.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/html/audio_midi/js/ui.js b/html/audio_midi/js/ui.js index 6c10dff..ab1b20b 100644 --- a/html/audio_midi/js/ui.js +++ b/html/audio_midi/js/ui.js @@ -572,6 +572,13 @@ function ui_create_number( parent_ele, d ) return ele; } + +function precisionRound(number, precision) +{ + var factor = Math.pow(10, precision); + return Math.round(number * factor) / factor; +} + function ui_set_number_display( ele_id, value ) { var ele = dom_id_to_ele(ele_id); @@ -579,11 +586,20 @@ function ui_set_number_display( ele_id, value ) if( typeof(value)=="number") { var val = value.toString(); - - if( ele.decpl == 0 ) - ele.innerHTML = parseInt(val,10); + + var defined_fl = (typeof ele.decpl !== 'undefined'); + + if( defined_fl ) + { + if( ele.decpl == 0 ) + ele.innerHTML = parseInt(val,10); + else + ele.innerHTML = precisionRound(parseFloat(val),ele.decpl) + } else - ele.innerHTML = parseFloat(val); + { + ele.innerHTML = parseFloat(val) + } } } @@ -617,7 +633,7 @@ function ui_create_text_display( parent_ele, d ) function ui_set_progress( ele, value ) { - var ele = dom_id_to_ele(ele_id); + //var ele = dom_id_to_ele(ele_id); ele.value = Math.round( ele.max * (value - ele.minValue) / (ele.maxValue - ele.minValue)); } From f0c8c08899f4c23555c42e29f30c0eda8fd7dc88 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:50:59 -0400 Subject: [PATCH 6/7] audio_midi/css : Added margins between rows. --- html/audio_midi/css/ui.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/html/audio_midi/css/ui.css b/html/audio_midi/css/ui.css index 509e421..131c04d 100644 --- a/html/audio_midi/css/ui.css +++ b/html/audio_midi/css/ui.css @@ -64,6 +64,8 @@ label { flex-direction: row; align-items: center; background-color: LightBlue; + margin-top: 10px; + margin-bottom: 10px; } .uiCol { From 8dad34106682ce66457ee1327daaaab37303fdf1 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 19 Apr 2025 13:51:18 -0400 Subject: [PATCH 7/7] audio_midi/ui.cfg : Added meter panel. --- html/audio_midi/ui.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/html/audio_midi/ui.cfg b/html/audio_midi/ui.cfg index 514fe44..60b6d91 100644 --- a/html/audio_midi/ui.cfg +++ b/html/audio_midi/ui.cfg @@ -43,5 +43,12 @@ button:{ name: openBtnId, title:"Open" }, button:{ name: saveBtnId, title:"Save" }, }, + + row: { + panel: { + name: "meterPanelId", + title: "Meters" + } + } } } \ No newline at end of file