Merge branch 'master' of https://gitea.currawongproject.org/cml/libcw
This commit is contained in:
commit
18ece08b53
@ -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<handle_t,audioBuf_t>(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,6 +276,7 @@ cw::rc_t cw::audio::buf::create( handle_t& hRef, unsigned devCnt, unsigned meter
|
||||
|
||||
p->devArray = mem::allocZ<cmApDev>(devCnt );
|
||||
p->devCnt = devCnt;
|
||||
p->meter_damp_coeff = meterDampCoeff;
|
||||
|
||||
hRef.set(p);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
|
2
cwIo.cpp
2
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;
|
||||
|
@ -47,7 +47,10 @@ namespace cw
|
||||
|
||||
kSaveBtnId,
|
||||
kOpenBtnId,
|
||||
kFnStringId
|
||||
kFnStringId,
|
||||
|
||||
kMeterPanelId,
|
||||
kBaseAudioMeterId
|
||||
};
|
||||
|
||||
enum
|
||||
@ -82,10 +85,21 @@ namespace cw
|
||||
{ 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
|
||||
{
|
||||
io::handle_t ioH;
|
||||
@ -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<bool> 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; i<app.audioInChCnt; ++i)
|
||||
mem::release(app.meterA[i].title);
|
||||
mem::release(app.meterA);
|
||||
|
||||
mem::release(app.directory);
|
||||
return kOkRC;
|
||||
}
|
||||
@ -361,11 +387,98 @@ namespace cw
|
||||
|
||||
}
|
||||
|
||||
rc_t _get_active_audio_dev_and_ch_count( app_t* app )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
unsigned i = 0;
|
||||
unsigned n = audioDeviceCount( app->ioH );
|
||||
for(unsigned i=0; i<n; ++i)
|
||||
if( audioDeviceIsActive(app->ioH,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; i<app->audioInChCnt; ++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; i<n; ++i)
|
||||
{
|
||||
double db = std::max(0.0, 20.0 * log10(agd->meterA[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");
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -64,6 +64,8 @@ label {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: LightBlue;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.uiCol {
|
||||
|
@ -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);
|
||||
@ -580,10 +587,19 @@ function ui_set_number_display( ele_id, value )
|
||||
{
|
||||
var val = value.toString();
|
||||
|
||||
var defined_fl = (typeof ele.decpl !== 'undefined');
|
||||
|
||||
if( defined_fl )
|
||||
{
|
||||
if( ele.decpl == 0 )
|
||||
ele.innerHTML = parseInt(val,10);
|
||||
else
|
||||
ele.innerHTML = parseFloat(val);
|
||||
ele.innerHTML = precisionRound(parseFloat(val),ele.decpl)
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
@ -43,5 +43,12 @@
|
||||
button:{ name: openBtnId, title:"Open" },
|
||||
button:{ name: saveBtnId, title:"Save" },
|
||||
},
|
||||
|
||||
row: {
|
||||
panel: {
|
||||
name: "meterPanelId",
|
||||
title: "Meters"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user