cwFlowProc.h/cpp,cwFlow.cpp,proc_dict.cfg : Added 'audio_silence'.
Added periodic console reporting from 'audio_meter'. Added gain based termination to 'midi_voice'. Added 'test_key_pitch' to 'piano_voice'.
This commit is contained in:
parent
c1231d48ef
commit
daa4e2355c
@ -43,6 +43,7 @@ namespace cw
|
||||
{ "audio_duplicate", &audio_duplicate::members },
|
||||
{ "audio_merge", &audio_merge::members },
|
||||
{ "audio_mix", &audio_mix::members },
|
||||
{ "audio_silence", &audio_silence::members },
|
||||
{ "sine_tone", &sine_tone::members },
|
||||
{ "pv_analysis", &pv_analysis::members },
|
||||
{ "pv_synthesis", &pv_synthesis::members },
|
||||
|
159
cwFlowProc.cpp
159
cwFlowProc.cpp
@ -2116,6 +2116,72 @@ namespace cw
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// audio_silence
|
||||
//
|
||||
namespace audio_silence
|
||||
{
|
||||
enum {
|
||||
kSratePId,
|
||||
kChCntPId,
|
||||
kOutPId
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
} inst_t;
|
||||
|
||||
|
||||
rc_t _create( proc_t* proc, inst_t* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
srate_t srate = 0;
|
||||
unsigned ch_cnt = 1;
|
||||
|
||||
|
||||
if((rc = var_register_and_get(proc, kAnyChIdx,
|
||||
kSratePId,"srate",kBaseSfxId,srate,
|
||||
kChCntPId,"ch_cnt",kBaseSfxId,ch_cnt)) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( srate == 0 )
|
||||
srate = proc->ctx->sample_rate;
|
||||
|
||||
|
||||
// create the output audio buffer
|
||||
rc = var_register_and_set( proc, "out", kBaseSfxId, kOutPId, kAnyChIdx, srate, ch_cnt, proc->ctx->framesPerCycle );
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t _destroy( proc_t* proc, inst_t* p )
|
||||
{ return kOkRC; }
|
||||
|
||||
rc_t _value( proc_t* proc, inst_t* p, variable_t* var )
|
||||
{ return kOkRC; }
|
||||
|
||||
rc_t _exec( proc_t* proc, inst_t* p )
|
||||
{ return kOkRC; }
|
||||
|
||||
rc_t _report( proc_t* proc, inst_t* p )
|
||||
{ return kOkRC; }
|
||||
|
||||
class_members_t members = {
|
||||
.create = std_create<inst_t>,
|
||||
.destroy = std_destroy<inst_t>,
|
||||
.value = std_value<inst_t>,
|
||||
.exec = std_exec<inst_t>,
|
||||
.report = std_report<inst_t>
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// sine_tone
|
||||
@ -3493,7 +3559,8 @@ namespace cw
|
||||
kPeakDbPId,
|
||||
kOutPId,
|
||||
kPeakFlPId,
|
||||
kClipFlPId
|
||||
kClipFlPId,
|
||||
kRptPeriodMsPId
|
||||
};
|
||||
|
||||
|
||||
@ -3503,25 +3570,32 @@ namespace cw
|
||||
{
|
||||
audio_meter_t** mtrA;
|
||||
unsigned mtrN;
|
||||
unsigned rptPeriodSmpN;
|
||||
unsigned rptPhase;
|
||||
} inst_t;
|
||||
|
||||
|
||||
rc_t create( proc_t* proc )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
const abuf_t* srcBuf = nullptr; //
|
||||
inst_t* inst = mem::allocZ<inst_t>();
|
||||
rc_t rc = kOkRC;
|
||||
const abuf_t* srcBuf = nullptr; //
|
||||
inst_t* inst = mem::allocZ<inst_t>();
|
||||
unsigned rptPeriodMs = 0;
|
||||
|
||||
proc->userPtr = inst;
|
||||
|
||||
// verify that a source buffer exists
|
||||
if((rc = var_register_and_get(proc, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC )
|
||||
if((rc = var_register_and_get(proc, kAnyChIdx,
|
||||
kInPId,"in",kBaseSfxId,srcBuf,
|
||||
kRptPeriodMsPId,"rpt_ms",kBaseSfxId,rptPeriodMs)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",proc->label);
|
||||
goto errLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->rptPeriodSmpN = (unsigned)(proc->ctx->sample_rate * rptPeriodMs/1000.0);
|
||||
|
||||
// allocate channel array
|
||||
inst->mtrN = srcBuf->chN;
|
||||
inst->mtrA = mem::allocZ<audio_meter_t*>( inst->mtrN );
|
||||
@ -3594,6 +3668,8 @@ namespace cw
|
||||
const abuf_t* srcBuf = nullptr;
|
||||
unsigned chN = 0;
|
||||
|
||||
bool rptFl = inst->rptPeriodSmpN != 0 && inst->rptPhase >= inst->rptPeriodSmpN;
|
||||
|
||||
// get the src buffer
|
||||
if((rc = var_get(proc,kInPId, kAnyChIdx, srcBuf )) != kOkRC )
|
||||
goto errLabel;
|
||||
@ -3606,8 +3682,20 @@ namespace cw
|
||||
var_set(proc, kOutPId, i, inst->mtrA[i]->outDb );
|
||||
var_set(proc, kPeakFlPId, i, inst->mtrA[i]->peakFl );
|
||||
var_set(proc, kClipFlPId, i, inst->mtrA[i]->clipFl );
|
||||
|
||||
if( rptFl )
|
||||
cwLogPrint("%6.2f ",inst->mtrA[i]->outDb);
|
||||
}
|
||||
|
||||
if(rptFl)
|
||||
{
|
||||
cwLogPrint("\n");
|
||||
inst->rptPhase -= inst->rptPeriodSmpN;
|
||||
}
|
||||
|
||||
inst->rptPhase += srcBuf->frameN;
|
||||
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
@ -4189,6 +4277,11 @@ namespace cw
|
||||
unsigned hzN;
|
||||
double* hzA; // hzA[128] - midi to Hz lookup table.
|
||||
|
||||
bool done_fl;
|
||||
coeff_t gain;
|
||||
coeff_t gain_coeff;
|
||||
coeff_t gain_thresh;
|
||||
|
||||
} inst_t;
|
||||
|
||||
|
||||
@ -4227,6 +4320,8 @@ namespace cw
|
||||
for(unsigned i=0; i<midi::kMidiNoteCnt; ++i)
|
||||
p->hzA[i] = midi_to_hz(i);
|
||||
|
||||
p->done_fl = true;
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
@ -4247,6 +4342,11 @@ namespace cw
|
||||
return rc;
|
||||
}
|
||||
|
||||
void _on_note_off( inst_t* p )
|
||||
{
|
||||
p->gain_coeff = 0.9;
|
||||
}
|
||||
|
||||
rc_t _exec( proc_t* proc, inst_t* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
@ -4272,11 +4372,18 @@ namespace cw
|
||||
p->cur_vel = m->d1;
|
||||
|
||||
if( m->d1 == 0 )
|
||||
var_set(proc,kDoneFlPId,kAnyChIdx,true);
|
||||
_on_note_off(p);
|
||||
else
|
||||
{
|
||||
p->done_fl = false;
|
||||
p->gain = (coeff_t)p->cur_vel / 127;
|
||||
p->gain_coeff = 1.0;
|
||||
p->gain_thresh = 0.001;
|
||||
}
|
||||
break;
|
||||
|
||||
case midi::kNoteOffMdId:
|
||||
var_set(proc,kDoneFlPId,kAnyChIdx,true);
|
||||
_on_note_off(p);
|
||||
break;
|
||||
|
||||
case midi::kPbendMdId:
|
||||
@ -4289,16 +4396,13 @@ namespace cw
|
||||
}
|
||||
|
||||
// if the voice is off then zero the audio buffer
|
||||
if( p->cur_vel == 0 )
|
||||
if( p->done_fl )
|
||||
{
|
||||
vop::zero(abuf->buf,abuf->frameN);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// calculate the gain based on the cur_vel
|
||||
coeff_t gain = (coeff_t)p->cur_vel / 127;
|
||||
|
||||
// fill in the audio buffer
|
||||
for(unsigned i=0; i<abuf->frameN; ++i)
|
||||
{
|
||||
@ -4306,12 +4410,21 @@ namespace cw
|
||||
double frac = p->wtPhase - j;
|
||||
sample_t smp = p->wtA[j] + (p->wtA[j+1] - p->wtA[j]) * frac;
|
||||
|
||||
abuf->buf[i] = gain*smp;
|
||||
abuf->buf[i] = p->gain*smp;
|
||||
|
||||
p->wtPhase += p->cur_hz + (p->cur_hz * p->cur_pbend);
|
||||
if( p->wtPhase >= p->wtN )
|
||||
p->wtPhase -= p->wtN;
|
||||
}
|
||||
|
||||
p->gain *= p->gain_coeff;
|
||||
|
||||
if( p->gain < p->gain_thresh )
|
||||
{
|
||||
var_set(proc,kDoneFlPId,kAnyChIdx,true);
|
||||
p->done_fl = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
errLabel:
|
||||
@ -4344,6 +4457,7 @@ namespace cw
|
||||
kOutPId,
|
||||
kDoneFlPId,
|
||||
kTestPitchPId,
|
||||
kKeyPitchPId,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -4374,7 +4488,8 @@ namespace cw
|
||||
coeff_t gain_coeff;
|
||||
bool done_fl;
|
||||
|
||||
unsigned test_pitch; // Base test pitch
|
||||
unsigned test_pitch; // Pitch under test or 0 if not on test mode
|
||||
unsigned test_key_pitch; // Key associated with lowest velocity when in test mode.
|
||||
unsigned test_pitchN; // Count of valid velocities for test_pitch
|
||||
unsigned* test_pitch_map; // test_pitch_map[ test_pitch_N ]
|
||||
|
||||
@ -4395,6 +4510,7 @@ namespace cw
|
||||
{
|
||||
assert( j < p->test_pitchN );
|
||||
p->test_pitch_map[j++] = i;
|
||||
//printf("%i %i %i\n",j-1,i,p->test_pitchN);
|
||||
}
|
||||
|
||||
}
|
||||
@ -4417,7 +4533,8 @@ namespace cw
|
||||
kWtbInstrPId, "wtb_instr", kBaseSfxId, wtb_instr,
|
||||
kInPId, "in", kBaseSfxId, mbuf,
|
||||
kDoneFlPId, "done_fl", kBaseSfxId, done_fl,
|
||||
kTestPitchPId, "test_pitch",kBaseSfxId, p->test_pitch)) != kOkRC )
|
||||
kTestPitchPId, "test_pitch",kBaseSfxId, p->test_pitch,
|
||||
kKeyPitchPId, "test_key_pitch", kBaseSfxId, p->test_key_pitch)) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
@ -4536,8 +4653,8 @@ namespace cw
|
||||
// if in voice test mode
|
||||
if( p->test_pitch_map != nullptr )
|
||||
{
|
||||
// if the the pitch is in side the test range
|
||||
if( d0 < p->test_pitch || p->test_pitch + p->test_pitchN <= d1 )
|
||||
// if the the pitch is inside the test range
|
||||
if( d0 < p->test_key_pitch || p->test_key_pitch + p->test_pitchN <= d0 )
|
||||
goto errLabel;
|
||||
|
||||
// then the pitch is set to the test pitch ...
|
||||
@ -4545,7 +4662,7 @@ namespace cw
|
||||
|
||||
// ... and the velocity is mapped to a vel for which there is a known vel in the wt-bank
|
||||
// Performed pitches above the test pitch trigger increasing velocities.
|
||||
d1 = p->test_pitch_map[ m->d0 - p->test_pitch ];
|
||||
d1 = p->test_pitch_map[ m->d0 - p->test_key_pitch ];
|
||||
}
|
||||
|
||||
// get the wave-table associated with the pitch and velocity
|
||||
@ -4598,14 +4715,20 @@ namespace cw
|
||||
else
|
||||
{
|
||||
|
||||
// for each channel
|
||||
for(unsigned i=0; i<kChCnt; ++i)
|
||||
{
|
||||
// for the output buffer
|
||||
sample_t* yV = abuf->buf + i*abuf->frameN;
|
||||
unsigned yi = 0;
|
||||
|
||||
// get this channels oscillator
|
||||
osc_state_t* osc = p->osc + i;
|
||||
|
||||
// for each sample in the output buffer
|
||||
while(yi < abuf->frameN)
|
||||
{
|
||||
// locate the current wavetable
|
||||
wt_bank::seg_t* seg = p->wt->chA[i].segA + osc->seg_idx;
|
||||
unsigned n;
|
||||
|
||||
@ -4639,7 +4762,7 @@ namespace cw
|
||||
|
||||
if( p->gain < p->kGainThreshold && !p->done_fl )
|
||||
{
|
||||
//printf("done\n");
|
||||
//printf("done:\n");
|
||||
var_set(proc,kDoneFlPId,kAnyChIdx,true);
|
||||
p->done_fl = true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ namespace cw
|
||||
namespace audio_duplicate { extern class_members_t members; }
|
||||
namespace audio_mix { extern class_members_t members; }
|
||||
namespace audio_marker { extern class_members_t members; }
|
||||
namespace audio_silence { extern class_members_t members; }
|
||||
namespace sine_tone { extern class_members_t members; }
|
||||
namespace pv_analysis { extern class_members_t members; }
|
||||
namespace pv_synthesis { extern class_members_t members; }
|
||||
|
@ -130,6 +130,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
audio_silence: {
|
||||
vars: {
|
||||
srate: { type:srate, value:0, flags:["init"], doc:"Signal sample rate. 0=Use default system sample rate"},
|
||||
ch_cnt: { type:uint, value:1, flags:["init"], doc:"Count of output audio channels. (e.g. 1=mono, 2=stereo, ...)"},
|
||||
out: { type:audio, doc:"Audio signal containing only 0."},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sine_tone: {
|
||||
vars: {
|
||||
@ -545,7 +553,8 @@
|
||||
peakDb: { type:coeff, value: -10.0, doc:"Peak threshold." },
|
||||
out: { type:coeff, value: 0.0, doc:"Meter output." },
|
||||
peakFl: { type:bool, value: false, doc:"Peak output." }
|
||||
clipFl: { type:bool, value: false, doc:"Clip indicator output."}
|
||||
clipFl: { type:bool, value: false, doc:"Clip indicator output."},
|
||||
rpt_ms: { type:uint, value:0, flags:["init"], doc:"Report period in ms or 0 for no report."},
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,7 +724,8 @@
|
||||
in: { type:midi, doc:"MIDI in" },
|
||||
out: { type:audio, doc:"Audio out" },
|
||||
done_fl: { type:bool, value:false, doc:"Triggers when voice is available."},
|
||||
test_pitch: { type:uint, value:0, doc:"Base testing pitch." },
|
||||
test_pitch: { type:uint, value:0, doc:"Pitch to test." },
|
||||
test_key_pitch: { type:uint, value:48, doc:"Base pitch to use for lowest velocity when in 'test' mode." },
|
||||
}
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user