TempleOSTS_130315.ISO
This commit is contained in:
1 parent
e57428affb
commit
17b71f1a2d
958 files changed
+26043
-15907
No files matched your search
@@ -0,0 +1,651 @@
|
||||
#help_index "Snd/HDAudio"
|
||||
|
||||
#define HD_1_CHAN 0
|
||||
#define HD_2_CHAN 1
|
||||
#define HD_3_CHAN 2
|
||||
#define HD_4_CHAN 3
|
||||
|
||||
#define HD_8_BIT 0
|
||||
#define HD_16_BIT 1
|
||||
#define HD_20_BIT 2
|
||||
#define HD_24_BIT 3
|
||||
#define HD_32_BIT 4
|
||||
|
||||
#define HD_48kHz 0
|
||||
|
||||
#define HD_DFT_OUT_FMT (HD_2_CHAN+HD_24_BIT<<4+HD_48kHz<<8)
|
||||
#define HD_DFT_IN_FMT (HD_2_CHAN+HD_16_BIT<<4+HD_48kHz<<8)
|
||||
|
||||
#define HD_POS_BUF_MULTIPLES 0x1000
|
||||
|
||||
#define HD_CORB_ENTRIES 256
|
||||
#define HD_RIRB_ENTRIES 256
|
||||
#define HD_BDL_ENTRIES 256
|
||||
|
||||
#define HD_GCTL 0x08
|
||||
#define HD_STATESTS 0x0E
|
||||
#define HD_GSTS 0x10
|
||||
#define HD_CORBLBASE 0x40
|
||||
#define HD_CORBUBASE 0x44
|
||||
#define HD_CORBWP 0x48
|
||||
#define HD_CORBRP 0x4A
|
||||
#define HD_CORBCTL 0x4C
|
||||
#define HD_CORBST 0x4D
|
||||
#define HD_RIRBLBASE 0x50
|
||||
#define HD_RIRBUBASE 0x54
|
||||
#define HD_RIRBWP 0x58
|
||||
#define HD_RIRBCTL 0x5C
|
||||
#define HD_RIRBSTS 0x5D
|
||||
|
||||
#define STRCTL 0x00
|
||||
#define STRSTS 0x03
|
||||
#define STRLPIB 0x04
|
||||
#define STRCBL 0x08
|
||||
#define STRLVI 0x0C
|
||||
#define STRFIFOW 0x0E
|
||||
#define STRFIFOS 0x10
|
||||
#define STRFMT 0x12
|
||||
#define STRBDPL 0x18
|
||||
#define STRBDPU 0x1C
|
||||
|
||||
#define ISTR0 0x080
|
||||
#define ISTR1 0x0A0
|
||||
#define ISTR2 0x0C0
|
||||
#define ISTR3 0x0E0
|
||||
#define OSTR0 0x100
|
||||
#define OSTR1 0x120
|
||||
#define OSTR2 0x140
|
||||
#define OSTR3 0x160
|
||||
|
||||
#define VERB_GET_PARAM 0xF0000
|
||||
#define VERB_CONNECT_SELECT_GET 0xF0100
|
||||
#define VERB_CONNECT_SELECT_SET 0x70100
|
||||
#define VERB_GET_CONNECT_LST 0xF0200
|
||||
#define VERB_PROCESS_STATE_GET 0xF0300
|
||||
#define VERB_PROCESS_STATE_SET 0x70300
|
||||
#define VERB_COEFF_INDEX_GET 0xD0000
|
||||
#define VERB_COEFF_INDEX_SET 0x50000
|
||||
#define VERB_PROCESS_COEFF_GET 0xC0000
|
||||
#define VERB_PROCESS_COEFF_SET 0x40000
|
||||
#define VERB_AMPLIFIER_GAIN_GET 0xB0000
|
||||
#define VERB_AMPLIFIER_GAIN_SET 0x30000
|
||||
#define VERB_STREAM_FMT_GET 0xA0000
|
||||
#define VERB_STREAM_FMT_SET 0x20000
|
||||
#define VERB_DIGIT_CONVERT1_GET 0xF0D00
|
||||
#define VERB_DIGIT_CONVERT1_SET 0x70D00
|
||||
#define VERB_DIGIT_CONVERT2_GET 0xF0D00
|
||||
#define VERB_DIGIT_CONVERT2_SET 0x70E00
|
||||
#define VERB_POWER_STATE_GET 0xF0500
|
||||
#define VERB_POWER_STATE_SET 0x70500
|
||||
#define VERB_CHAN_STREAM_ID_GET 0xF0600
|
||||
#define VERB_CHAN_STREAM_ID_SET 0x70600
|
||||
#define VERB_SDI_SELECT_GET 0xF0400
|
||||
#define VERB_SDI_SELECT_SET 0x70400
|
||||
#define VERB_PIN_WIDGET_CTL_GET 0xF0700
|
||||
#define VERB_PIN_WIDGET_CTL_SET 0x70700
|
||||
#define VERB_UNSOL_ENABLE_GET 0xF0800
|
||||
#define VERB_UNSOL_ENABLE_SET 0x70800
|
||||
#define VERB_PIN_SENSE_GET 0xF0900
|
||||
#define VERB_PIN_SENSE_SET 0x70900
|
||||
#define VERB_EAPDBTL_ENABLE_GET 0xF0C00
|
||||
#define VERB_EAPDBTL_ENABLE_SET 0x70C00
|
||||
#define VERB_BEEP_CTL_GET 0xF0A00
|
||||
#define VERB_BEEP_CTL_SET 0x70A00
|
||||
#define VERB_GPI_CTRL0_GET 0xF1000
|
||||
#define VERB_GPI_CTRL0_SET 0x71000
|
||||
#define VERB_GPI_CTRL1_GET 0xF1100
|
||||
#define VERB_GPI_CTRL1_SET 0x71100
|
||||
#define VERB_GPI_CTRL2_GET 0xF1200
|
||||
#define VERB_GPI_CTRL2_SET 0x71200
|
||||
#define VERB_GPI_CTRL3_GET 0xF1300
|
||||
#define VERB_GPI_CTRL3_SET 0x71300
|
||||
#define VERB_GPI_CTRL4_GET 0xF1400
|
||||
#define VERB_GPI_CTRL4_SET 0x71400
|
||||
#define VERB_GPI_CTRL5_GET 0xF1500
|
||||
#define VERB_GPI_CTRL5_SET 0x71500
|
||||
#define VERB_GPI_CTRL6_GET 0xF1600
|
||||
#define VERB_GPI_CTRL6_SET 0x71600
|
||||
#define VERB_GPI_CTRL7_GET 0xF1700
|
||||
#define VERB_GPI_CTRL7_SET 0x71700
|
||||
#define VERB_GPI_CTRL8_GET 0xF1800
|
||||
#define VERB_GPI_CTRL8_SET 0x71800
|
||||
#define VERB_GPI_CTRL9_GET 0xF1900
|
||||
#define VERB_GPI_CTRL9_SET 0x71900
|
||||
#define VERB_GPI_CTRLA_GET 0xF1A00
|
||||
#define VERB_GPI_CTRLA_SET 0x71A00
|
||||
#define VERB_VOL_CTL_GET 0xF0F00
|
||||
#define VERB_VOL_CTL_SET 0x70F00
|
||||
#define VERB_SUB_SYS_ID0_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID0_SET 0x72000
|
||||
#define VERB_SUB_SYS_ID1_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID1_SET 0x72100
|
||||
#define VERB_SUB_SYS_ID2_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID2_SET 0x72200
|
||||
#define VERB_SUB_SYS_ID3_GET 0xF2000
|
||||
#define VERB_SUB_SYS_ID3_SET 0x72300
|
||||
#define VERB_CFG_DFT0_GET 0xF1C00
|
||||
#define VERB_CFG_DFT0_SET 0x71C00
|
||||
#define VERB_CFG_DFT1_GET 0xF1C00
|
||||
#define VERB_CFG_DFT1_SET 0x71D00
|
||||
#define VERB_CFG_DFT2_GET 0xF1C00
|
||||
#define VERB_CFG_DFT2_SET 0x71E00
|
||||
#define VERB_CFG_DFT3_GET 0xF1C00
|
||||
#define VERB_CFG_DFT3_SET 0x71F00
|
||||
#define VERB_STRIPE_CTL_GET 0xF2400
|
||||
#define VERB_STRIPE_CTL_SET 0x72400
|
||||
#define VERB_RST 0x7FF00
|
||||
|
||||
|
||||
//Parameters
|
||||
#define P_VENDOR_ID 0x00
|
||||
#define P_REVISION_ID 0x02
|
||||
#define P_SUBNODE_CNT 0x04
|
||||
#define P_FUN_GRP_TYPE 0x05
|
||||
#define P_AUDIO_FUN_CAP 0x08
|
||||
#define P_AUDIO_WIDGET_CAP 0x09
|
||||
#define P_SAMPLE_SIZE_RATE_CAP 0x0A
|
||||
#define P_STREAM_FMTS 0x0B
|
||||
#define P_PIN_CAP 0x0C
|
||||
#define P_INPUT_AMP_CAP 0x0D
|
||||
#define P_OUTPUT_AMP_CAP 0x12
|
||||
#define P_CONNECT_LST_LEN 0x0E
|
||||
#define P_POWER_STATES 0x0F
|
||||
#define P_PROCESSING_CAP 0x10
|
||||
#define P_GPIO_CNT 0x11
|
||||
#define P_VOL_KNOB_CAP 0x13
|
||||
|
||||
//Function Group Types
|
||||
//00 reserved
|
||||
#define FGT_AUDIO 1
|
||||
#define FGT_VENDOR_MODEM 2
|
||||
//03-7F reserved
|
||||
//80-FF vendor function group
|
||||
|
||||
//Audio Widget Types
|
||||
#define AWT_OUTPUT 0x0
|
||||
#define AWT_INPUT 0x1
|
||||
#define AWT_MIXER 0x2
|
||||
#define AWT_SELECTOR 0x3
|
||||
#define AWT_PIN_COMPLEX 0x4
|
||||
#define AWT_POWER_WIDGET 0x5
|
||||
#define AWT_VOL_KNOB_WIDGET 0x6
|
||||
#define AWT_BEEP_GEN_WIDGET 0x7
|
||||
#define AWT_VENDOR 0xF
|
||||
#define AWT_NODE 0x10
|
||||
DefineLstLoad("ST_AUDIO_WIDGET_TYPES",
|
||||
"Output\0Input\0Mixer\0Selector\0Pin Complex\0"
|
||||
"Power Widget\0Vol Knob\0Beep Gen\0 \0 \0 \0 \0 \0 \0 \0Vendor\0Node\0");
|
||||
|
||||
class CHDBufDesc
|
||||
{
|
||||
I32 *buf;
|
||||
U32 len;
|
||||
U32 ctrl;
|
||||
};
|
||||
|
||||
#define HD_TONES 8
|
||||
|
||||
class CHDAudioCtrl
|
||||
{
|
||||
U8 *bar;
|
||||
I64 cad;
|
||||
U32 *corb;
|
||||
I64 *rirb;
|
||||
CHDBufDesc *ostr0_bdl,*istr0_bdl;
|
||||
SND_OUT_CONTAINER *ostr0_buf[2],*o_temp_buf;
|
||||
SND_IN_CONTAINER *istr0_buf[2];
|
||||
CTask *task;
|
||||
I64 waveform;
|
||||
F64 freq,amp;
|
||||
CSndWaveCtrl *tone_swcs[HD_TONES];
|
||||
U8 rirb_rp,corb_wp;
|
||||
Bool audio_task_started,in_running,out_running;
|
||||
} *_hda=NULL;
|
||||
|
||||
I64 AudioSize()
|
||||
{//$LK,"MemRep","MN:MemRep"$ uses this for Adam Heap
|
||||
I64 result=MSize2(snd_reverb_buf);
|
||||
if (_hda) {
|
||||
result+=MSize2(_hda)+MSize2(_hda->o_temp_buf);
|
||||
/* uncached heap
|
||||
result+=MSize2(_hda->corb)+MSize(_hda->rirb)+
|
||||
MSize2(_hda->ostr0_bdl)+MSize2(_hda->istr0_bdl);
|
||||
for (i=0;i<2;i++)
|
||||
result+=MSize2(_hda->ostr0_buf[i]);
|
||||
for (i=0;i<2;i++)
|
||||
result+=MSize2(_hda->istr0_buf[i]);
|
||||
*/
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
U0 HDSyncCORB()
|
||||
{
|
||||
U16 *wp,*rp;
|
||||
wp =_hda->bar+HD_CORBWP;
|
||||
*wp=_hda->corb_wp;
|
||||
rp =_hda->bar+HD_CORBRP;
|
||||
while (*rp&255!=_hda->corb_wp)
|
||||
Yield;
|
||||
}
|
||||
|
||||
U0 HDWriteCORB(I64 cad,I64 nid,U32 val)
|
||||
{
|
||||
val|=cad<<28+nid<<20;
|
||||
_hda->corb[++_hda->corb_wp]=val;
|
||||
}
|
||||
|
||||
I64 HDSyncRIRB()
|
||||
{
|
||||
U16 *_w;
|
||||
I64 wp,result=0;
|
||||
_w=_hda->bar+HD_RIRBWP;
|
||||
wp=*_w;
|
||||
while (_hda->rirb_rp!=wp)
|
||||
result=_hda->rirb[++_hda->rirb_rp];
|
||||
return result;
|
||||
}
|
||||
|
||||
I64 HDReadRIRB()
|
||||
{
|
||||
U16 *_w;
|
||||
I64 wp,result=0;
|
||||
_w=_hda->bar+HD_RIRBWP;
|
||||
do {
|
||||
Yield;
|
||||
wp=*_w;
|
||||
} while (wp==_hda->rirb_rp);
|
||||
result=_hda->rirb[++_hda->rirb_rp];
|
||||
return result;
|
||||
}
|
||||
|
||||
I64 HDWriteCORBSync(I64 cad,I64 nid,U32 val)
|
||||
{
|
||||
HDSyncCORB;
|
||||
HDSyncRIRB;
|
||||
HDWriteCORB(cad,nid,val);
|
||||
HDSyncCORB;
|
||||
return HDReadRIRB;
|
||||
}
|
||||
|
||||
Bool HDTestCORBSync(I64 cad,I64 nid,U32 val)
|
||||
{ //Checks for a response
|
||||
U16 *_w;
|
||||
U8 wp;
|
||||
|
||||
HDSyncCORB;
|
||||
HDSyncRIRB;
|
||||
HDWriteCORB(cad,nid,val);
|
||||
HDSyncCORB;
|
||||
|
||||
Sleep(1);
|
||||
_w=_hda->bar+HD_RIRBWP;
|
||||
wp=*_w;
|
||||
if (wp==_hda->rirb_rp)
|
||||
return FALSE;
|
||||
HDReadRIRB;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 HDTraverse(I64 cad,I64 nid)
|
||||
{
|
||||
I64 i,len,aud_cap,type;
|
||||
HDWriteCORBSync(cad,nid,VERB_POWER_STATE_SET+0x00); //0 is on
|
||||
HDWriteCORBSync(cad,nid,VERB_EAPDBTL_ENABLE_SET+0x02);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x02);
|
||||
HDWriteCORBSync(cad,nid,VERB_CONNECT_SELECT_SET+0x00);
|
||||
aud_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_SUBNODE_CNT);
|
||||
if (aud_cap.u16[0]) {
|
||||
for (i=aud_cap.u16[1];i<aud_cap.u16[1]+aud_cap.u16[0];i++)
|
||||
HDTraverse(cad,i);
|
||||
} else {
|
||||
aud_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_AUDIO_WIDGET_CAP);
|
||||
type=aud_cap>>20&15;
|
||||
if (Bt(&aud_cap,8))
|
||||
len=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_CONNECT_LST_LEN)&127;
|
||||
else
|
||||
len=0;
|
||||
HDWriteCORBSync(cad,nid,VERB_AMPLIFIER_GAIN_SET+0xF07F); //set I/O amp #0
|
||||
for (i=1;i<len;i++)
|
||||
HDWriteCORBSync(cad,nid,VERB_AMPLIFIER_GAIN_SET+0x7080+i<<8); //Set IN amps to mute
|
||||
switch (type) {
|
||||
case AWT_OUTPUT:
|
||||
if (FALSE) //if disabled
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x10);
|
||||
HDWriteCORBSync(cad,nid,VERB_STREAM_FMT_SET+HD_DFT_OUT_FMT);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x01);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
if (TRUE) //if disabled
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(cad,nid,VERB_CHAN_STREAM_ID_SET+0x20);
|
||||
HDWriteCORBSync(cad,nid,VERB_STREAM_FMT_SET+HD_DFT_IN_FMT);
|
||||
HDWriteCORBSync(cad,nid,VERB_PROCESS_STATE_SET+0x01);
|
||||
break;
|
||||
case AWT_PIN_COMPLEX:
|
||||
HDWriteCORBSync(cad,nid,VERB_PIN_WIDGET_CTL_SET+0xE2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDRun(Bool in,Bool out)
|
||||
{
|
||||
U32 *_d;
|
||||
if (_hda->bar) {
|
||||
if (out) {
|
||||
_d=_hda->bar+OSTR0+STRCTL;
|
||||
*_d=0x100002;
|
||||
_hda->out_running=TRUE;
|
||||
}
|
||||
if (in) {
|
||||
_d=_hda->bar+ISTR0+STRCTL;
|
||||
*_d=0x200002;
|
||||
_hda->in_running=TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDStop(Bool in,Bool out)
|
||||
{
|
||||
U32 *_d;
|
||||
if (_hda->bar) {
|
||||
if (out) {
|
||||
_d=_hda->bar+OSTR0+STRCTL;
|
||||
*_d=0;
|
||||
_hda->out_running=FALSE;
|
||||
}
|
||||
if (in) {
|
||||
_d=_hda->bar+ISTR0+STRCTL;
|
||||
*_d=0;
|
||||
_hda->in_running=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDSnd(F64 freq,I64 waveform=WF_SQUARE,F64 amp=1.0)
|
||||
{
|
||||
_hda->waveform=waveform;
|
||||
_hda->amp=amp;
|
||||
_hda->freq=freq;
|
||||
}
|
||||
|
||||
U0 HDFillBuf(SND_OUT_CONTAINER *buf,I64)
|
||||
{
|
||||
I64 i,size=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
if (!_hda->o_temp_buf)
|
||||
_hda->o_temp_buf=AMAlloc(size);
|
||||
MemSet(_hda->o_temp_buf,0,size);
|
||||
for (i=0;i<HD_TONES;i++)
|
||||
SndWaveAddBuf(_hda->tone_swcs[i],_hda->o_temp_buf,SND_BUF_LEN/SND_OCHANNELS,_hda->freq,_hda->waveform,snd_vol*_hda->amp);
|
||||
MemCpy(buf,_hda->o_temp_buf,size);
|
||||
}
|
||||
|
||||
U0 HDAudioTaskEndCB()
|
||||
{
|
||||
I64 i;
|
||||
HDStop(FALSE,TRUE);
|
||||
fp_snd=NULL;
|
||||
for (i=0;i<HD_TONES;i++) {
|
||||
SndWaveCtrlDel(_hda->tone_swcs[i]);
|
||||
_hda->tone_swcs[i]=NULL;
|
||||
}
|
||||
Exit;
|
||||
}
|
||||
|
||||
public U0 HDTonesInit()
|
||||
{
|
||||
I64 i;
|
||||
if (_hda) {
|
||||
for (i=0;i<HD_TONES;i++) {
|
||||
_hda->tone_swcs[i]->freq_multiplier=1.0;
|
||||
_hda->tone_swcs[i]->amp_multiplier=0;
|
||||
}
|
||||
_hda->tone_swcs[0]->amp_multiplier=1.0;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDAudioTask(I64)
|
||||
{
|
||||
//I didn't feel like messing around with PCI interrupts
|
||||
//so this task polls every millisecond to know when to
|
||||
//switch buffers.
|
||||
I64 i,next_obuf_trigger=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER)/2,
|
||||
obuf_rollover=0,
|
||||
next_ibuf_trigger=SND_BUF_LEN*sizeof(SND_IN_CONTAINER),
|
||||
ibuf_rollover=0;
|
||||
U32 *pos_in_obuf=_hda->bar+OSTR0+STRLPIB,
|
||||
*pos_in_ibuf=_hda->bar+ISTR0+STRLPIB;
|
||||
Fs->task_end_cb=&HDAudioTaskEndCB;
|
||||
for (i=0;i<HD_TONES;i++)
|
||||
_hda->tone_swcs[i]=SndWaveCtrlNew;
|
||||
HDTonesInit;
|
||||
_hda->freq=0;
|
||||
Snd(0);
|
||||
fp_snd=&HDSnd;
|
||||
fp_snd_fill_buf=&HDFillBuf;
|
||||
fp_snd_copy_buf=NULL;
|
||||
if (!IsSysDeterministic)
|
||||
Preempt(ON);
|
||||
snd_obuf_num=1;
|
||||
snd_ibuf_num=1;
|
||||
HDRun(FALSE,TRUE);
|
||||
_hda->audio_task_started=TRUE; //This flag is probably not necessary
|
||||
while (TRUE) {
|
||||
if (next_obuf_trigger-obuf_rollover<=*pos_in_obuf<next_obuf_trigger-obuf_rollover+(HD_POS_BUF_MULTIPLES-1)*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER)) {
|
||||
next_obuf_trigger+=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
if (next_obuf_trigger-obuf_rollover>=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER))
|
||||
obuf_rollover+=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
if (fp_snd_fill_buf) {
|
||||
LBts(&snd_flags,Sf_FILLING_OUT);
|
||||
(*fp_snd_fill_buf)(_hda->ostr0_buf[snd_obuf_num&1],snd_obuf_num);
|
||||
if (IsMute)
|
||||
MemSet(_hda->ostr0_buf[snd_obuf_num&1],0,SND_BUF_LEN*sizeof(SND_OUT_CONTAINER));
|
||||
else if (snd_reverb_intensity &&
|
||||
0<snd_reverb_delay<10.0)
|
||||
SndReverb(_hda->ostr0_buf[snd_obuf_num&1],snd_obuf_num);
|
||||
LBtr(&snd_flags,Sf_FILLING_OUT);
|
||||
}
|
||||
snd_obuf_num++;
|
||||
}
|
||||
if (next_ibuf_trigger-ibuf_rollover<=*pos_in_ibuf<next_ibuf_trigger-ibuf_rollover+(HD_POS_BUF_MULTIPLES-1)*SND_BUF_LEN*sizeof(SND_IN_CONTAINER)) {
|
||||
next_ibuf_trigger+=SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
if (next_ibuf_trigger-ibuf_rollover>=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_IN_CONTAINER))
|
||||
ibuf_rollover+=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
if (fp_snd_copy_buf)
|
||||
(*fp_snd_copy_buf)(_hda->istr0_buf[snd_obuf_num&1],snd_ibuf_num);
|
||||
snd_ibuf_num++;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDRst()
|
||||
{
|
||||
U32 d,*_d;
|
||||
HDStop(TRUE,TRUE);
|
||||
_d=_hda->bar+HD_GCTL;
|
||||
*_d=0; //rst
|
||||
do {
|
||||
Sleep(1);
|
||||
d=*_d;
|
||||
} while (d & 1);
|
||||
*_d=1;
|
||||
do {
|
||||
Sleep(1);
|
||||
d=*_d;
|
||||
} while (!(d & 1));
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
public U0 HDAudioEnd(Bool rst=TRUE)
|
||||
{
|
||||
snd_dev=SD_PC_SPEAKER;
|
||||
if (_hda && _hda->bar) {
|
||||
Kill(_hda->task);
|
||||
_hda->task=NULL;
|
||||
if (rst)
|
||||
HDRst;
|
||||
Free(_hda->corb);
|
||||
Free(_hda->rirb);
|
||||
Free(_hda->o_temp_buf);
|
||||
Free(_hda->ostr0_buf[0]);
|
||||
Free(_hda->ostr0_buf[1]);
|
||||
Free(_hda->istr0_buf[0]);
|
||||
Free(_hda->istr0_buf[1]);
|
||||
Free(_hda->ostr0_bdl);
|
||||
Free(_hda->istr0_bdl);
|
||||
Mem32DevFree(_hda->bar);
|
||||
Free(_hda);
|
||||
_hda=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public Bool HDAudioInit(I64 hd_bus,I64 hd_dev,I64 hd_fun)
|
||||
{
|
||||
I64 i;
|
||||
U32 *_d;
|
||||
U16 w,*_w;
|
||||
U8 *_b;
|
||||
if (_hda)
|
||||
HDAudioEnd;
|
||||
if (PCIReadU16(hd_bus,hd_dev,hd_fun,0)==0x8086 &&
|
||||
(_hda=ACAlloc(sizeof(CHDAudioCtrl))) &&
|
||||
(_hda->bar=Mem32DevAlloc(0x4000,0x4000)) ) {
|
||||
PCIWriteU32(hd_bus,hd_dev,hd_fun,0x14,_hda->bar(I64).u32[1]);
|
||||
PCIWriteU32(hd_bus,hd_dev,hd_fun,0x10,_hda->bar(I64).u32[0]);
|
||||
PCIWriteU16(hd_bus,hd_dev,hd_fun,0x04,
|
||||
PCIReadU16(hd_bus,hd_dev,hd_fun,0x04)|0x406);
|
||||
|
||||
HDRst;
|
||||
|
||||
_hda->corb=CAllocAligned(HD_CORB_ENTRIES*sizeof(U32),128,sys_uncached_heap);
|
||||
_d=_hda->bar+HD_CORBLBASE;
|
||||
*_d=_hda->corb(I64).u32[0];
|
||||
_d=_hda->bar+HD_CORBUBASE;
|
||||
*_d=_hda->corb(I64).u32[1];
|
||||
|
||||
_hda->rirb=CAllocAligned(HD_RIRB_ENTRIES*sizeof(I64),128,sys_uncached_heap);
|
||||
_d=_hda->bar+HD_RIRBLBASE;
|
||||
*_d=_hda->rirb(I64).u32[0];
|
||||
_d=_hda->bar+HD_RIRBUBASE;
|
||||
*_d=_hda->rirb(I64).u32[1];
|
||||
|
||||
_w=_hda->bar+HD_CORBRP;
|
||||
*_w=0x8000; //Rst read ptr
|
||||
do {
|
||||
Yield;
|
||||
w=*_w;
|
||||
} while (!(w&0x8000));
|
||||
*_w=0x0000; //Rst read ptr
|
||||
do {
|
||||
Yield;
|
||||
w=*_w;
|
||||
} while (w&0x8000);
|
||||
|
||||
_w=_hda->bar+HD_RIRBWP;
|
||||
*_w=0x8000; //Rst write ptr
|
||||
|
||||
_b=_hda->bar+HD_CORBCTL;
|
||||
*_b=0x02; //Run
|
||||
_b=_hda->bar+HD_RIRBCTL;
|
||||
*_b=0x02; //Run
|
||||
|
||||
_w=_hda->bar+HD_CORBWP;
|
||||
_hda->corb_wp=*_w;
|
||||
_w=_hda->bar+HD_RIRBWP;
|
||||
_hda->rirb_rp=*_w;
|
||||
|
||||
_hda->ostr0_bdl =CAllocAligned(HD_BDL_ENTRIES*sizeof(CHDBufDesc),128,sys_uncached_heap);
|
||||
_d=_hda->bar+OSTR0+STRBDPL;
|
||||
*_d=_hda->ostr0_bdl(I64).u32[0];
|
||||
_d=_hda->bar+OSTR0+STRBDPU;
|
||||
*_d=_hda->ostr0_bdl(I64).u32[1];
|
||||
for (i=0;i<2;i++) {
|
||||
_hda->ostr0_bdl[i].buf=_hda->ostr0_buf[i]=CAllocAligned(SND_BUF_LEN*sizeof(SND_OUT_CONTAINER),128,sys_uncached_heap);
|
||||
_hda->ostr0_bdl[i].len=SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
_hda->ostr0_bdl[i].ctrl=1;
|
||||
}
|
||||
|
||||
_hda->istr0_bdl =CAllocAligned(HD_BDL_ENTRIES*sizeof(CHDBufDesc),128,sys_uncached_heap);
|
||||
_d=_hda->bar+ISTR0+STRBDPL;
|
||||
*_d=_hda->istr0_bdl(I64).u32[0];
|
||||
_d=_hda->bar+ISTR0+STRBDPU;
|
||||
*_d=_hda->istr0_bdl(I64).u32[1];
|
||||
for (i=0;i<2;i++) {
|
||||
_hda->istr0_bdl[i].buf=_hda->istr0_buf[i]=CAllocAligned(SND_BUF_LEN*sizeof(SND_IN_CONTAINER),128,sys_uncached_heap);
|
||||
_hda->istr0_bdl[i].len=SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
_hda->istr0_bdl[i].ctrl=1;
|
||||
}
|
||||
|
||||
_w=_hda->bar+HD_STATESTS;
|
||||
w=*_w;
|
||||
while (w) {
|
||||
_hda->cad=Bsf(w);
|
||||
if (HDTestCORBSync(_hda->cad,0,VERB_GET_PARAM+P_SUBNODE_CNT)) {
|
||||
HDTraverse(_hda->cad,0);
|
||||
|
||||
_d=_hda->bar+OSTR0+STRLPIB;
|
||||
*_d=0;
|
||||
_d=_hda->bar+OSTR0+STRCBL;
|
||||
*_d=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_OUT_CONTAINER);
|
||||
_w=_hda->bar+OSTR0+STRLVI;
|
||||
*_w=1; //last valid index
|
||||
_w=_hda->bar+OSTR0+STRFMT;
|
||||
*_w=HD_DFT_OUT_FMT;
|
||||
|
||||
_d=_hda->bar+ISTR0+STRLPIB;
|
||||
*_d=0;
|
||||
_d=_hda->bar+ISTR0+STRCBL;
|
||||
*_d=HD_POS_BUF_MULTIPLES*SND_BUF_LEN*sizeof(SND_IN_CONTAINER);
|
||||
_w=_hda->bar+ISTR0+STRLVI;
|
||||
*_w=1; //last valid index
|
||||
_w=_hda->bar+ISTR0+STRFMT;
|
||||
*_w=HD_DFT_IN_FMT;
|
||||
|
||||
LBts(&sys_semas[SYS_SEMA_SND],0); //turn off until cfg completed
|
||||
LBtr(&snd_flags,Sf_FILLING_OUT);
|
||||
_hda->audio_task_started=FALSE;
|
||||
if (mp_cnt>1)
|
||||
_hda->task=MPSpawn(&HDAudioTask,NULL,"HD Audio");
|
||||
else
|
||||
_hda->task=Spawn(&HDAudioTask,NULL,"HD Audio");
|
||||
while (!_hda->audio_task_started)
|
||||
Yield;
|
||||
snd_dev=SD_HD_AUDIO;
|
||||
return TRUE;
|
||||
}
|
||||
Btr(&w,_hda->cad);
|
||||
}
|
||||
HDAudioEnd(FALSE);
|
||||
} else {
|
||||
Free(_hda);
|
||||
_hda=NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool HDAudioScan()
|
||||
{
|
||||
I64 i=-1,j;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x040300,++i);
|
||||
if (j<0)
|
||||
return FALSE;
|
||||
|
||||
//!!! Remove the following line. !!!
|
||||
if (j.u8[1]!=0x1B) break;
|
||||
//!!! We got problems with $LK,"0xF0000000","FF:::/TempleOS/Kernel/Memory.CPP,0xF000000"$ !!!
|
||||
|
||||
if (HDAudioInit(j.u8[2],j.u8[1],j.u8[0]))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
HDAudioScan;
|
||||
|
||||
//$BK,1$Run $LK-A,"::/TempleOS/Adam/Snd/HDCfg.CPP"$.$BK,0$
|
||||
#help_index ""
|
||||
@@ -0,0 +1,638 @@
|
||||
#define MAX_CONNECTS 16
|
||||
|
||||
class MyMass:CMass
|
||||
{
|
||||
F64 radius;
|
||||
U8 nid,type,num_connects,cur_connect;
|
||||
U32 audio_widget_capabilities;
|
||||
U8 connect_lst[MAX_CONNECTS];
|
||||
U8 gain_lst[MAX_CONNECTS];
|
||||
U32 pin_capabilities,pin_sense,
|
||||
pcm_size_rates,
|
||||
in_amp_cap,out_amp_cap;
|
||||
U8 pin_widget_ctl;
|
||||
Bool disabled;
|
||||
};
|
||||
|
||||
class MySpring:CSpring
|
||||
{
|
||||
I64 color;
|
||||
};
|
||||
|
||||
CMathODE *ode=NULL;
|
||||
|
||||
#define BORDER 10
|
||||
|
||||
|
||||
U0 DrawIt(CTask *task,CDC *dc)
|
||||
{
|
||||
Bool old_suspend,old_preempt;
|
||||
I16 *buf;
|
||||
I64 i,cxx,cyy,
|
||||
cy=task->win_pixel_height>>1;
|
||||
F64 dx,dy,d;
|
||||
MyMass *tempm;
|
||||
MySpring *temps;
|
||||
|
||||
old_preempt=Preempt(OFF);
|
||||
old_suspend=Suspend(task);
|
||||
temps=ode->next_spring;
|
||||
while (temps!=&ode->next_spring) {
|
||||
dc->color=temps->color;
|
||||
GrLine(dc,temps->end1->x,temps->end1->y,
|
||||
temps->end2->x,temps->end2->y);
|
||||
cxx=(temps->end1->x+temps->end2->x)/2;
|
||||
cyy=(temps->end1->y+temps->end2->y)/2;
|
||||
dx=temps->end1->x-temps->end2->x;
|
||||
dy=temps->end1->y-temps->end2->y;
|
||||
d=Sqrt(dx*dx+dy*dy);
|
||||
dx/=d;
|
||||
dy/=d;
|
||||
GrLine(dc,cxx,cyy,cxx+3.0*dy-3.0*dx,cyy-3.0*dx-3.0*dy);
|
||||
GrLine(dc,cxx,cyy,cxx-3.0*dy-3.0*dx,cyy+3.0*dx-3.0*dy);
|
||||
temps=temps->next;
|
||||
}
|
||||
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
if (tempm->disabled)
|
||||
dc->color=BLUE;
|
||||
else
|
||||
dc->color=LTBLUE;
|
||||
GrCircle(dc,tempm->x,tempm->y,tempm->radius);
|
||||
GrPrintF(dc,tempm->x,tempm->y-FONT_HEIGHT/2,"%02X %3tZ",
|
||||
tempm->nid,tempm->type,
|
||||
"ST_AUDIO_WIDGET_TYPES");
|
||||
tempm=tempm->next;
|
||||
}
|
||||
Suspend(task,old_suspend);
|
||||
Preempt(old_preempt);
|
||||
dc->color=BLUE;
|
||||
buf=_hda->istr0_buf[0];
|
||||
for (i=0;i<SND_BUF_LEN;i++)
|
||||
GrPlot(dc,i*task->win_pixel_width/SND_BUF_LEN,
|
||||
cy-buf[i]*cy/MAX_I16);
|
||||
}
|
||||
|
||||
|
||||
U0 MyDerivative(CMathODE *ode,F64,COrder2D3 *,COrder2D3 *)
|
||||
{
|
||||
//The forces due to springs and drag are
|
||||
//automatically handled by the
|
||||
//ode code. We can add new forces
|
||||
//here.
|
||||
CTask *task=ode->win_task;
|
||||
I64 h=task->win_pixel_width,v=task->win_pixel_height;
|
||||
F64 d,dd;
|
||||
CD3 p;
|
||||
MyMass *tempm1,*tempm2;
|
||||
|
||||
tempm1=ode->next_mass;
|
||||
while (tempm1!=&ode->next_mass) {
|
||||
tempm2=tempm1->next;
|
||||
while (tempm2!=&ode->next_mass) {
|
||||
D3Sub(&tempm2->state->x,&tempm1->state->x,&p);
|
||||
dd=D3SqrNorm(&p);
|
||||
if (dd<=Sqr(tempm1->radius+tempm2->radius)) {
|
||||
d=Sqrt(dd)+0.0001;
|
||||
dd=10.0*Sqr(Sqr(Sqr(tempm1->radius+tempm2->radius)-dd));
|
||||
D3MulEqu(&p,dd/d);
|
||||
D3AddEqu(&tempm2->DstateDt->DxDt,&p);
|
||||
D3SubEqu(&tempm1->DstateDt->DxDt,&p);
|
||||
} else {
|
||||
D3MulEqu(&p,100000.0/dd);
|
||||
D3AddEqu(&tempm2->DstateDt->DxDt,&p);
|
||||
D3SubEqu(&tempm1->DstateDt->DxDt,&p);
|
||||
}
|
||||
tempm2=tempm2->next;
|
||||
}
|
||||
if (tempm1->state->x<BORDER)
|
||||
tempm1->DstateDt->DxDt+=1000*Sqr(tempm1->state->x-BORDER);
|
||||
if (tempm1->state->y<BORDER)
|
||||
tempm1->DstateDt->DyDt+=1000*Sqr(tempm1->state->y-BORDER);
|
||||
if (tempm1->state->x>h-BORDER-FONT_WIDTH*6)
|
||||
tempm1->DstateDt->DxDt-=1000*Sqr(tempm1->state->x-(h-BORDER-FONT_WIDTH*6));
|
||||
if (tempm1->state->y>v-BORDER)
|
||||
tempm1->DstateDt->DyDt-=1000*Sqr(tempm1->state->y-(v-BORDER));
|
||||
tempm1=tempm1->next;
|
||||
}
|
||||
}
|
||||
|
||||
MyMass *PlaceMass(I64 nid)
|
||||
{
|
||||
MyMass *tempm=CAlloc(sizeof(MyMass));
|
||||
tempm->mass=1.0;
|
||||
tempm->drag_profile_factor=100.0;
|
||||
tempm->radius=5;
|
||||
tempm->nid=nid;
|
||||
tempm->gain_lst[0]=0x7F;
|
||||
MemSet(tempm->gain_lst+1,0x80,(MAX_CONNECTS-1)*sizeof(U8));
|
||||
QueIns(tempm,ode->last_mass);
|
||||
return tempm;
|
||||
}
|
||||
|
||||
MyMass *FindMassByNID(I64 nid)
|
||||
{
|
||||
MyMass *tempm;
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
if (tempm->nid==nid)
|
||||
return tempm;
|
||||
tempm=tempm->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MyMass *FindMassByXY(I64 x,I64 y)
|
||||
{
|
||||
I64 dd,best_dd=MAX_I64;
|
||||
MyMass *tempm,*result=NULL;
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
dd=SqrI64(tempm->x-x)+SqrI64(tempm->y-y);
|
||||
if (dd<best_dd) {
|
||||
result=tempm;
|
||||
best_dd=dd;
|
||||
}
|
||||
tempm=tempm->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
I64 FindConnectIndex(MyMass *tempm,I64 nid)
|
||||
{
|
||||
I64 i;
|
||||
for (i=0;i<tempm->num_connects;i++)
|
||||
if (tempm->connect_lst[i]==nid)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
MySpring *PlaceSpring(MyMass *tempm1,MyMass *tempm2)
|
||||
{
|
||||
MySpring *temps=CAlloc(sizeof(MySpring));
|
||||
temps->end1=tempm1;
|
||||
temps->end2=tempm2;
|
||||
temps->constant=10;
|
||||
temps->rest_len=0;
|
||||
temps->color=LTGRAY;
|
||||
QueIns(temps,ode->last_spring);
|
||||
return temps;
|
||||
}
|
||||
|
||||
U0 RedoSprings()
|
||||
{
|
||||
I64 i,k;
|
||||
MyMass *tempm,*tempm1;
|
||||
MySpring *temps;
|
||||
|
||||
QueDel(&ode->next_spring,TRUE);
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
for (i=0;i<tempm->num_connects;i++) {
|
||||
if ((k=tempm->connect_lst[i]) &&
|
||||
(tempm1=FindMassByNID(k)) ) {
|
||||
temps=PlaceSpring(tempm,tempm1);
|
||||
switch (tempm->type) {
|
||||
case AWT_MIXER:
|
||||
if (!(tempm->gain_lst[i]&0x80)) { //If not mute
|
||||
temps->color=GREEN;
|
||||
temps->constant=100;
|
||||
}
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
case AWT_SELECTOR:
|
||||
case AWT_PIN_COMPLEX:
|
||||
case AWT_VENDOR:
|
||||
if (i==tempm->cur_connect) {
|
||||
temps->color=RED;
|
||||
temps->constant=100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tempm=tempm->next;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Init()
|
||||
{
|
||||
ode=ODENew(0,1e-4,ODEF_HAS_MASSES);
|
||||
ode->derivative=&MyDerivative;
|
||||
ode->drag_v2=0.002;
|
||||
ode->drag_v3=0.00001;
|
||||
ode->acceleration_limit=5e3;
|
||||
|
||||
QueIns(ode,Fs->last_ode);
|
||||
}
|
||||
|
||||
U0 CleanUp()
|
||||
{
|
||||
QueRem(ode);
|
||||
QueDel(&ode->next_mass,TRUE);
|
||||
QueDel(&ode->next_spring,TRUE);
|
||||
ODEDel(ode);
|
||||
}
|
||||
|
||||
U0 HDCfgConnectLst(MyMass *tempm,I64 cad,I64 nid)
|
||||
{
|
||||
I64 i,j,connection_lst_len;
|
||||
j=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_CONNECT_LST_LEN);
|
||||
connection_lst_len=j&127;
|
||||
if (j&128) { //Long form?
|
||||
for (i=0;i<connection_lst_len;i+=2) {
|
||||
j=HDWriteCORBSync(cad,nid,VERB_GET_CONNECT_LST+i);
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u16[0];
|
||||
if (i+1<connection_lst_len)
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u16[1];
|
||||
}
|
||||
} else {
|
||||
for (i=0;i<connection_lst_len;i+=4) {
|
||||
j=HDWriteCORBSync(cad,nid,VERB_GET_CONNECT_LST+i);
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u8[0];
|
||||
if (i+1<connection_lst_len)
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u8[1];
|
||||
if (i+2<connection_lst_len)
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u8[2];
|
||||
if (i+3<connection_lst_len)
|
||||
tempm->connect_lst[tempm->num_connects++]=j.u8[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDCfgTraverse(I64 cad,I64 nid)
|
||||
{
|
||||
I64 i,j;
|
||||
MyMass *tempm=PlaceMass(nid);
|
||||
j=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_SUBNODE_CNT);
|
||||
if (j.u16[0]) {
|
||||
tempm->type=AWT_NODE;
|
||||
for (i=j.u16[1];i<j.u16[1]+j.u16[0];i++)
|
||||
HDCfgTraverse(cad,i);
|
||||
} else {
|
||||
tempm->audio_widget_capabilities=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_AUDIO_WIDGET_CAP);
|
||||
tempm->pcm_size_rates=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_SAMPLE_SIZE_RATE_CAP);
|
||||
tempm->in_amp_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_INPUT_AMP_CAP);
|
||||
tempm->out_amp_cap=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_OUTPUT_AMP_CAP);
|
||||
tempm->type=tempm->audio_widget_capabilities>>20&15;
|
||||
switch (tempm->type) {
|
||||
case AWT_PIN_COMPLEX:
|
||||
tempm->pin_widget_ctl=HDWriteCORBSync(cad,nid,VERB_PIN_WIDGET_CTL_GET);
|
||||
tempm->pin_capabilities=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_PIN_CAP);
|
||||
if (Bt(&tempm->pin_capabilities,0) ||
|
||||
Bt(&tempm->pin_capabilities,2))
|
||||
tempm->pin_sense=HDWriteCORBSync(cad,nid,VERB_PIN_SENSE_GET);
|
||||
HDWriteCORBSync(cad,nid,VERB_CONNECT_SELECT_SET+0x00);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
tempm->disabled=TRUE;
|
||||
case AWT_SELECTOR:
|
||||
case AWT_VENDOR:
|
||||
HDWriteCORBSync(cad,nid,VERB_CONNECT_SELECT_SET+0x00);
|
||||
break;
|
||||
}
|
||||
if (Bt(&tempm->audio_widget_capabilities,8))
|
||||
HDCfgConnectLst(tempm,cad,nid);
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDCfgRandomizeXY()
|
||||
{
|
||||
I64 h=Fs->win_pixel_width,v=Fs->win_pixel_height;
|
||||
MyMass *tempm;
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
tempm->x=RandU32%(h-2*BORDER-FONT_WIDTH*6)+BORDER;
|
||||
tempm->y=RandU32%(v-2*BORDER)+BORDER;
|
||||
tempm=tempm->next;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDCfgPopUpInfoTask(MyMass *tempm)
|
||||
{
|
||||
I64 i;
|
||||
"$$FG,RED$$NID:$$FG$$0x%02X $$FG,RED$$Type:$$FG$$%Z\n",
|
||||
tempm->nid,tempm->type,"ST_AUDIO_WIDGET_TYPES";
|
||||
|
||||
i=tempm->audio_widget_capabilities;
|
||||
"\n$$FG,RED$$Audio Widget Capabilities:$$FG$$\n";
|
||||
if (Bt(&i,0))
|
||||
"Stereo, ";
|
||||
if (Bt(&i,1))
|
||||
"In Amp, ";
|
||||
if (Bt(&i,2))
|
||||
"Out Amp, ";
|
||||
if (Bt(&i,3))
|
||||
"Amp Override, ";
|
||||
if (Bt(&i,4))
|
||||
"Fmt Override, ";
|
||||
if (Bt(&i,5))
|
||||
"Stripe, ";
|
||||
if (Bt(&i,6))
|
||||
"Proc Wgt, ";
|
||||
if (Bt(&i,7))
|
||||
"Unsolicited, ";
|
||||
if (Bt(&i,8))
|
||||
"Cnt Lst, ";
|
||||
if (Bt(&i,9))
|
||||
"Digital, ";
|
||||
if (Bt(&i,10))
|
||||
"Power Ctrl, ";
|
||||
if (Bt(&i,11))
|
||||
"Left/Right Swap, ";
|
||||
"Delay:%d\n",i.u16[1]&0xF;
|
||||
|
||||
i=tempm->in_amp_cap;
|
||||
"\n$$FG,RED$$Input Amp Capabilities:$$FG$$\n"
|
||||
"Offset:0x%02X Steps:0x%02X StepSize:%5.2fdB Mutable:%d\n",
|
||||
i&127,i.u8[1]&127+1,0.25*(i.u16[1]&127),Bt(&i,31);
|
||||
|
||||
i=tempm->out_amp_cap;
|
||||
"\n$$FG,RED$$Output Amp Capabilities:$$FG$$\n"
|
||||
"Offset:0x%02X Steps:0x%02X StepSize:%5.2fdB Mutable:%d\n",
|
||||
i&127,i.u8[1]&127+1,0.25*(i.u16[1]&127),Bt(&i,31);
|
||||
|
||||
"\n$$FG,RED$$Size Rates Capabilities:$$FG$$\n";
|
||||
for (i=0;i<21;i++)
|
||||
if (Bt(&tempm->pcm_size_rates,i))
|
||||
"%z",i,
|
||||
" 8.0kHz\0 11.025kHz\0 16.0kHz\0 22.05kHz\0"
|
||||
" 32.0kHz\0 44.1kHz\0 48.0kHz\0 88.2kHz\0"
|
||||
" 96.0kHz\0 176.4kHz\0 192.0kHz\0 384kHz\0"
|
||||
" \0 \0 \0 \0"
|
||||
" 8Bit\0 16bit\0 20Bit\0 24Bit\0 32Bit\0";
|
||||
NewLine;
|
||||
|
||||
|
||||
"\n$$FG,RED$$Connection Lst:$$FG$$\n";
|
||||
for (i=0;i<tempm->num_connects;i++)
|
||||
"%02X,",tempm->connect_lst[i];
|
||||
NewLine;
|
||||
|
||||
"\n$$FG,RED$$Gain Lst:$$FG$$\n";
|
||||
for (i=0;i<tempm->num_connects;i++)
|
||||
"%02X,",tempm->gain_lst[i];
|
||||
NewLine;
|
||||
|
||||
switch (tempm->type) {
|
||||
case AWT_PIN_COMPLEX:
|
||||
"\n$$FG,RED$$Pin Capabilities:$$FG$$\n";
|
||||
i=tempm->pin_capabilities;
|
||||
if (Bt(&i,0))
|
||||
"Impedance Sense, ";
|
||||
if (Bt(&i,1))
|
||||
"Trigger Required, ";
|
||||
if (Bt(&i,2))
|
||||
"Presence Detect, ";
|
||||
if (Bt(&i,3))
|
||||
"Headphone Drive, ";
|
||||
if (Bt(&i,4))
|
||||
"Output, ";
|
||||
if (Bt(&i,5))
|
||||
"Input, ";
|
||||
if (Bt(&i,6))
|
||||
"Balanced, ";
|
||||
if (Bt(&i,16))
|
||||
"EAPD, ";
|
||||
"Vref:%02X\n\n",i.u8[1];
|
||||
if (Bt(&tempm->pin_capabilities,0) ||
|
||||
Bt(&tempm->pin_capabilities,2))
|
||||
tempm->pin_sense=HDWriteCORBSync(_hda->cad,tempm->nid,VERB_PIN_SENSE_GET);
|
||||
if (Bt(&tempm->pin_capabilities,0))
|
||||
"Impedance Measurement:%08X\n",tempm->pin_sense&0x7FFFFFFF;
|
||||
if (Bt(&tempm->pin_capabilities,2))
|
||||
"Presence:%d\n",Bt(&tempm->pin_sense,31);
|
||||
"\n\nPin widget ctrl bits:\n"
|
||||
" 7: High phn enable (low impedance output amp)\n"
|
||||
" 6: Output Enable\n"
|
||||
" 5: Input Enable\n"
|
||||
"0-2: Vref 0=HiZ 1=50% 2=Gnd 4=80% 5=100%\n";
|
||||
tempm->pin_widget_ctl=PmtI64("Widget Ctrl (0x%02X):",tempm->pin_widget_ctl,0,0xFF);
|
||||
HDWriteCORBSync(_hda->cad,tempm->nid,VERB_PIN_WIDGET_CTL_SET+tempm->pin_widget_ctl);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
"Disable";
|
||||
if (tempm->disabled=YorN)
|
||||
HDWriteCORBSync(_hda->cad,tempm->nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(_hda->cad,tempm->nid,VERB_CHAN_STREAM_ID_SET+0x20);
|
||||
NewLine;
|
||||
break;
|
||||
case AWT_OUTPUT:
|
||||
"Disable";
|
||||
if (tempm->disabled=YorN)
|
||||
HDWriteCORBSync(_hda->cad,tempm->nid,VERB_CHAN_STREAM_ID_SET+0x00);
|
||||
else
|
||||
HDWriteCORBSync(_hda->cad,tempm->nid,VERB_CHAN_STREAM_ID_SET+0x10);
|
||||
NewLine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDCfgPopUpInfo(MyMass *tempm)
|
||||
{
|
||||
U8 buf[136];
|
||||
SPrintF(buf,"HDCfgPopUpInfoTask(0x%X);\"\\n\\nPress SHIFT-ESC\\n\\n\\n\\n\";View;",tempm);
|
||||
Fs->win_inhibit|=WIF_ODE;
|
||||
Fs->draw_it=NULL;
|
||||
WinMgrSync;
|
||||
PopUp(buf,Fs);
|
||||
Fs->win_inhibit&=~WIF_ODE;
|
||||
Fs->draw_it=&DrawIt;
|
||||
}
|
||||
|
||||
U0 HDCfgEdLink(MyMass *tempm_out,MyMass *tempm_in)
|
||||
{
|
||||
I64 i,j;
|
||||
if ((i=FindConnectIndex(tempm_in,tempm_out->nid))>=0) {
|
||||
switch (tempm_in->type) {
|
||||
case AWT_MIXER:
|
||||
MemSet(tempm_in->gain_lst,0x80,sizeof(U8)*MAX_CONNECTS);
|
||||
tempm_in->gain_lst[i]=0x7F;
|
||||
for (j=0;j<tempm_in->num_connects;j++)
|
||||
HDWriteCORBSync(_hda->cad,tempm_in->nid,
|
||||
VERB_AMPLIFIER_GAIN_SET+0x7000+tempm_in->gain_lst[j]+j<<8);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
case AWT_SELECTOR:
|
||||
case AWT_PIN_COMPLEX:
|
||||
case AWT_VENDOR:
|
||||
tempm_in->cur_connect=i;
|
||||
HDWriteCORBSync(_hda->cad,tempm_in->nid,VERB_CONNECT_SELECT_SET+i);
|
||||
break;
|
||||
}
|
||||
RedoSprings;
|
||||
}
|
||||
}
|
||||
|
||||
U0 HDCfgSave()
|
||||
{
|
||||
CDoc *doc=DocNew;
|
||||
I64 i;
|
||||
MyMass *tempm;
|
||||
DocPutS(doc,"//This file was generated by $$LK,\"::/TempleOS/Adam/Snd/HDCfg.CPP.Z\",\"FI:::/TempleOS/Adam/Snd/HDCfg.CPP\"$$\n\n"
|
||||
"U0 MyHDCfg()\n{\n");
|
||||
tempm=ode->next_mass;
|
||||
while (tempm!=&ode->next_mass) {
|
||||
DocPrintF(doc," //0x%02X %Z\n",tempm->nid,tempm->type,"ST_AUDIO_WIDGET_TYPES");
|
||||
if (tempm->num_connects) {
|
||||
DocPutS(doc," //Connection Lst:");
|
||||
for (i=0;i<tempm->num_connects;i++) {
|
||||
if (i==tempm->cur_connect)
|
||||
DocPutS(doc,"*");
|
||||
DocPrintF(doc,"0x%02X ",tempm->connect_lst[i]);
|
||||
}
|
||||
DocPutS(doc,"\n");
|
||||
if (tempm->type==AWT_MIXER) {
|
||||
DocPutS(doc," //Gain Lst:");
|
||||
for (i=0;i<tempm->num_connects;i++)
|
||||
DocPrintF(doc,"0x%02X ",tempm->gain_lst[i]);
|
||||
DocPutS(doc,"\n");
|
||||
}
|
||||
}
|
||||
switch (tempm->type) {
|
||||
case AWT_OUTPUT:
|
||||
if (tempm->disabled)
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_CHAN_STREAM_ID_SET+0x00);\n",
|
||||
tempm->nid);
|
||||
else
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_CHAN_STREAM_ID_SET+0x10);\n",
|
||||
tempm->nid);
|
||||
break;
|
||||
case AWT_MIXER:
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_AMPLIFIER_GAIN_SET+0xB07F);\n",
|
||||
tempm->nid);
|
||||
for (i=0;i<tempm->num_connects;i++)
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_AMPLIFIER_GAIN_SET+0x%04X);\n",
|
||||
tempm->nid,0x7000+tempm->gain_lst[i]+i<<8);
|
||||
break;
|
||||
case AWT_INPUT:
|
||||
if (tempm->disabled)
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_CHAN_STREAM_ID_SET+0x00);\n",
|
||||
tempm->nid);
|
||||
else
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_CHAN_STREAM_ID_SET+0x20);\n",
|
||||
tempm->nid);
|
||||
goto here;
|
||||
case AWT_PIN_COMPLEX:
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_PIN_WIDGET_CTL_SET+0x%02X);\n",
|
||||
tempm->nid,tempm->pin_widget_ctl);
|
||||
case AWT_SELECTOR:
|
||||
case AWT_VENDOR:
|
||||
here:
|
||||
if (tempm->num_connects>1)
|
||||
DocPrintF(doc," HDWriteCORBSync(_hda->cad,0x%02X,VERB_CONNECT_SELECT_SET+0x%02X);\n",
|
||||
tempm->nid,tempm->cur_connect);
|
||||
break;
|
||||
}
|
||||
DocPutS(doc,"\n");
|
||||
tempm=tempm->next;
|
||||
}
|
||||
DocPutS(doc," LBtr(&sys_semas[SYS_SEMA_SND],0);\n"
|
||||
"}\n\nif (snd_dev==SD_HD_AUDIO)\n"
|
||||
" MyHDCfg;\n");
|
||||
StrCpy(doc->filename.name,"HOME/HDAudioCfg.CPP.Z");
|
||||
DocWrite(doc);
|
||||
DocDel(doc);
|
||||
}
|
||||
|
||||
U0 HDCfg()
|
||||
{
|
||||
I64 p1,p2;
|
||||
MyMass *tempm1=NULL,*tempm2=NULL;
|
||||
|
||||
if (snd_dev!=SD_HD_AUDIO) {
|
||||
"HD Audio not detected\n";
|
||||
return;
|
||||
}
|
||||
HDAudioInit(0,27,0);
|
||||
|
||||
MenuPush(
|
||||
"File {"
|
||||
" Abort(,CH_SHIFT_ESC);"
|
||||
" Exit(,CH_ESC);"
|
||||
"}"
|
||||
"Edit {"
|
||||
" Randomize(,'\n');"
|
||||
" Options(,CH_SPACE);"
|
||||
"}"
|
||||
);
|
||||
SettingsPush; //See $LK,"SettingsPush","MN:SettingsPush"$
|
||||
Preempt(OFF);
|
||||
DocBottom;
|
||||
WordStat;
|
||||
WinMax;
|
||||
WinBorder;
|
||||
Fs->win_inhibit=WIF_IP_L|WIF_IP_R|WIF_DBL_CLICK|WIF_DOC;
|
||||
Init;
|
||||
|
||||
HDCfgTraverse(_hda->cad,0);
|
||||
HDCfgRandomizeXY;
|
||||
RedoSprings;
|
||||
DocCursor;
|
||||
DocClear;
|
||||
Fs->draw_it=&DrawIt;
|
||||
PopUpOk(
|
||||
"This is a tool to cfgure\n"
|
||||
"HD Audio. It creates $$FG,RED$$HOME/HDAudioCfg.CPP.Z$$FG$$\n"
|
||||
"which you should $$FG,GREEN$$#include$$FG$$ in your\n"
|
||||
"$$FG,RED$$HOME/Adam3cSnd.CPP.Z$$FG$$ file.\n\n\n"
|
||||
"Left click to see info and cfgure a widget.\n"
|
||||
"Right click drag to connect output to input.\n\n"
|
||||
"You will need to set input and output amplifier\n"
|
||||
"gains by hand -- edit $$FG,RED$$HOME/HDAudioCfg.CPP.Z$$FG$$.\n\n"
|
||||
"The $$FG,BLUE$$BLUE$$FG$$ line in the middle is microphone waveform.\n\n"
|
||||
);
|
||||
|
||||
HDRun(TRUE,TRUE); //run input output
|
||||
Snd(500,WF_SINE,0.50);
|
||||
|
||||
try {
|
||||
while (TRUE) {
|
||||
switch (GetMsg(&p1,&p2,1<<MSG_IP_L_UP|1<<MSG_IP_R_DOWN|1<<MSG_IP_R_UP|1<<MSG_KEY_DOWN)) {
|
||||
case MSG_IP_L_UP:
|
||||
if (tempm1=FindMassByXY(p1,p2))
|
||||
HDCfgPopUpInfo(tempm1);
|
||||
tempm1=NULL;
|
||||
break;
|
||||
case MSG_IP_R_DOWN:
|
||||
tempm1=FindMassByXY(p1,p2);
|
||||
break;
|
||||
case MSG_IP_R_UP:
|
||||
tempm2=FindMassByXY(p1,p2);
|
||||
if (tempm1 && tempm2)
|
||||
HDCfgEdLink(tempm1,tempm2);
|
||||
break;
|
||||
case MSG_KEY_DOWN:
|
||||
switch (p1) {
|
||||
case CH_SPACE:
|
||||
if (tempm1=FindMassByXY(ipx-Fs->win_pixel_left-Fs->win_scroll_x,ipy-Fs->win_pixel_top-Fs->win_scroll_y))
|
||||
HDCfgPopUpInfo(tempm1);
|
||||
tempm1=NULL;
|
||||
break;
|
||||
case '\n':
|
||||
HDCfgRandomizeXY;
|
||||
break;
|
||||
case CH_ESC:
|
||||
HDCfgSave;
|
||||
case CH_SHIFT_ESC:
|
||||
goto hd_done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
hd_done: //Don't goto out of try
|
||||
GetMsg(,,1<<MSG_KEY_UP);
|
||||
} catch
|
||||
Fs->catch_except=TRUE;
|
||||
SettingsPop;
|
||||
HDStop(TRUE,FALSE); //stop input
|
||||
CleanUp;
|
||||
MenuPop;
|
||||
"$$BK,1$$Note: #include \"HOME/HDAudioCfg\" in your start-up scripts.$$BK,0$$\n";
|
||||
}
|
||||
|
||||
HDCfg;
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
#help_index "Snd/Math;Math"
|
||||
public F64 Saw(F64 t,F64 period)
|
||||
{ //0.0 - 1.0 think "(Sin+1)/2"
|
||||
if (period) {
|
||||
if (t>=0.0)
|
||||
return t%period/period;
|
||||
else
|
||||
return 1.0+t%period/period;
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public F64 FullSaw(F64 t,F64 period)
|
||||
{ //1.0 - -1.0 think "Sin"
|
||||
if (period) {
|
||||
if (t>=0.0)
|
||||
return 2.0*(t%period/period)-1.0;
|
||||
else
|
||||
return 2.0*(t%period/period)+1.0;
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public F64 Caw(F64 t,F64 period)
|
||||
{ //1.0 - 0.0 think "(Cos+1)/2"
|
||||
if (period) {
|
||||
if (t>=0.0)
|
||||
return 1.0-t%period/period;
|
||||
else
|
||||
return -(t%period)/period;
|
||||
} else
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public F64 FullCaw(F64 t,F64 period)
|
||||
{ //1.0 - -1.0 think "Cos"
|
||||
if (period) {
|
||||
if (t>=0.0)
|
||||
return -2.0*(t%period/period)+1.0;
|
||||
else
|
||||
return -2.0*(t%period/period)-1.0;
|
||||
} else
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public F64 Tri(F64 t,F64 period)
|
||||
{ //0.0 - 1.0 - 0.0
|
||||
if (period) {
|
||||
t=2.0*(Abs(t)%period)/period;
|
||||
if (t<=1.0)
|
||||
return t;
|
||||
else
|
||||
return 2.0-t;
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
public F64 FullTri(F64 t,F64 period)
|
||||
{ //0.0 - 1.0 - 0.0 - -1.0 -0.0
|
||||
if (period) {
|
||||
t=4.0*(t%period)/period;
|
||||
if (t<=-1.0) {
|
||||
if (t<=-3.0)
|
||||
return t+4.0;
|
||||
else
|
||||
return -2.0-t;
|
||||
} else {
|
||||
if (t<=1.0)
|
||||
return t;
|
||||
else if (t<=3.0)
|
||||
return 2.0-t;
|
||||
else
|
||||
return t-4.0;
|
||||
}
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#help_index "Snd/Math"
|
||||
public F64 Note2Freq(I64 note,I64 octave=3)
|
||||
{
|
||||
return 440.0*2.0`(octave-3+note/12.0);
|
||||
}
|
||||
|
||||
|
||||
F64 SinPhaseCont(F64 last_y,F64 last_dydt,
|
||||
F64 current_amp,F64 phase_offset)
|
||||
{
|
||||
F64 phase;
|
||||
phase=last_y/current_amp;
|
||||
if (phase>1.0) phase=1.0;
|
||||
if (phase<-1.0) phase=-1.0;
|
||||
if (last_dydt<0)
|
||||
phase=ã-ASin(phase);
|
||||
else
|
||||
phase=ASin(phase);
|
||||
return phase-phase_offset;
|
||||
}
|
||||
|
||||
public CSndWaveCtrl *SndWaveCtrlNew(I64 sample_rate=SND_SAMPLE_RATE,I64 sample_bits=SND_SAMPLE_BITS,
|
||||
I64 channels=SND_OCHANNELS,CTask *mem_task=NULL)
|
||||
{
|
||||
CSndWaveCtrl *swc=CAlloc(sizeof(CSndWaveCtrl),mem_task);
|
||||
swc->freq_multiplier=1.0;
|
||||
swc->amp_multiplier=1.0;
|
||||
swc->sample_rate=sample_rate;
|
||||
swc->sample_bits=sample_bits;
|
||||
swc->channels=channels;
|
||||
swc->last_dydt=1.0;
|
||||
return swc;
|
||||
}
|
||||
|
||||
public U0 SndWaveCtrlDel(CSndWaveCtrl *swc)
|
||||
{
|
||||
Free(swc);
|
||||
}
|
||||
|
||||
public U0 SndWaveAddBuf(CSndWaveCtrl *swc,U8 *buf,I64 num_samples,
|
||||
F64 _freq,I64 _waveform=WF_SQUARE,F64 _amp=1.0,F64 _left=1.0, F64 _right=1.0)
|
||||
{
|
||||
//num_samples is multiplied by channels to get buf_len.
|
||||
//left,right range from 0.0-1.0
|
||||
//Supports 16,24 and 32 bits
|
||||
I64 reg i,reg j,reg k;
|
||||
F64 a,f,amp,reg phase;
|
||||
if (!swc) return;
|
||||
_freq*=swc->freq_multiplier;
|
||||
_amp*=swc->amp_multiplier;
|
||||
if (!_freq||!_amp) {
|
||||
swc->last_y=swc->phase=0;
|
||||
swc->last_dydt=1.0;
|
||||
} else {
|
||||
phase=swc->phase;
|
||||
i=0;
|
||||
amp=Min(MAX_I32,MAX_I32*_amp);
|
||||
f=2*ã/swc->sample_rate*_freq;
|
||||
switch (_waveform) {
|
||||
case WF_NOISE:
|
||||
a=2.0/ã*amp;
|
||||
break;
|
||||
case WF_SAWTOOTH:
|
||||
a=amp/ã;
|
||||
break;
|
||||
case WF_SINE:
|
||||
phase=SinPhaseCont(swc->last_y,swc->last_dydt,amp,0.0);
|
||||
break;
|
||||
}
|
||||
while (phase<0)
|
||||
phase+=2*ã;
|
||||
while (phase>=2*ã)
|
||||
phase-=2*ã;
|
||||
num_samples*=swc->channels;
|
||||
while (i<num_samples) {
|
||||
switch (_waveform) {
|
||||
case WF_SQUARE:
|
||||
if (phase>=ã)
|
||||
j=-amp;
|
||||
else
|
||||
j=amp;
|
||||
break;
|
||||
case WF_SINE:
|
||||
j=amp*Sin(phase);
|
||||
break;
|
||||
case WF_TRIANGLE:
|
||||
if (phase>=ã) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=-amp*Sign(swc->last_y)+.00001;
|
||||
phase-=ã;
|
||||
}
|
||||
j=(swc->last_y*(ã-phase)+swc->next_y*phase)/ã;
|
||||
break;
|
||||
case WF_SAWTOOTH:
|
||||
j=a*(phase-ã);
|
||||
break;
|
||||
case WF_NOISE:
|
||||
if (phase<ã) {
|
||||
if (phase<f) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=a*RandI16/MAX_U16;
|
||||
}
|
||||
j=swc->last_y*(ã-phase)+swc->next_y*phase;
|
||||
} else {
|
||||
if (phase-ã<f) {
|
||||
swc->last_y=swc->next_y;
|
||||
swc->next_y=a*RandI16/MAX_U16;
|
||||
}
|
||||
j=swc->last_y*(2.0*ã-phase)+swc->next_y*(phase-ã);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//left channel
|
||||
k=j*_left;
|
||||
if (swc->sample_bits==16) {
|
||||
k>>=16;
|
||||
buf(I16 *)[i++]+=k;
|
||||
} else {
|
||||
if (swc->sample_bits==24)
|
||||
k&=0xFFFFFF00;
|
||||
buf(I32 *)[i++]+=k;
|
||||
}
|
||||
//right channel
|
||||
if (swc->channels==2) {
|
||||
k=j*_right;
|
||||
if (swc->sample_bits==16) {
|
||||
k>>=16;
|
||||
buf(I16 *)[i++]+=k;
|
||||
} else {
|
||||
if (swc->sample_bits==24)
|
||||
k&=0xFFFFFF00;
|
||||
buf(I32 *)[i++]+=k;
|
||||
}
|
||||
}
|
||||
phase+=f;
|
||||
while (phase>=2*ã)
|
||||
phase-=2*ã;
|
||||
}
|
||||
if (_waveform==WF_SINE) {
|
||||
swc->last_y=amp*Sin(phase);
|
||||
swc->last_dydt=Cos(phase);
|
||||
}
|
||||
swc->phase=phase;
|
||||
}
|
||||
}
|
||||
|
||||
#help_index "Snd/HDAudio"
|
||||
I64 snd_reverb_buf_cnt;
|
||||
SND_OUT_CONTAINER *snd_reverb_buf=NULL;
|
||||
|
||||
U0 SndReverb(SND_OUT_CONTAINER *buf,I64 buf_num)
|
||||
{
|
||||
I64 i,j,mask,span=RoundI64(SND_SAMPLE_RATE*SND_OCHANNELS*snd_reverb_delay,SND_OCHANNELS);
|
||||
if (!snd_reverb_buf || span>snd_reverb_buf_cnt) {
|
||||
Free(snd_reverb_buf);
|
||||
snd_reverb_buf_cnt=1<<(Bsr(span)+1);
|
||||
snd_reverb_buf=ACAlloc(snd_reverb_buf_cnt*sizeof(SND_OUT_CONTAINER));
|
||||
}
|
||||
j=buf_num*SND_BUF_LEN;
|
||||
mask=snd_reverb_buf_cnt-1;
|
||||
for (i=0;i<SND_BUF_LEN;i++,j++) {
|
||||
snd_reverb_buf[j&mask]=
|
||||
buf[i]=
|
||||
LimitI64(buf[i]+snd_reverb_intensity*snd_reverb_buf[(j-span)&mask],
|
||||
MIN_I32,MAX_I32)&0xFFFFFF00;
|
||||
}
|
||||
}
|
||||
|
||||
I64 AudioSize()
|
||||
{
|
||||
return MSize2(snd_reverb_buf);
|
||||
}
|
||||
|
||||
#help_index "Snd"
|
||||
@@ -0,0 +1,260 @@
|
||||
#help_index "Snd/Music"
|
||||
U8 *cur_song=NULL;
|
||||
CTask *cur_song_task=NULL;
|
||||
I64 music_octave;
|
||||
F64 music_note_len;
|
||||
U8 music_note_map[7]={0,2,3,5,7,8,10};
|
||||
I64 music_mute=0;
|
||||
I64 music_waveform,music_meter_top,music_meter_bottom;
|
||||
public F64 music_tempo,music_stacatto_factor,music_amplitude;
|
||||
|
||||
//This is if you wish to sync with a
|
||||
//note in a Play() string. 0 is the start
|
||||
public I64 music_play_note_num=0;
|
||||
|
||||
#help_index "Snd/Music;Time/Seconds"
|
||||
F64 music_tM_correction=0,music_last_tMBeat=0,music_last_tM=0;
|
||||
public F64 tM()
|
||||
{
|
||||
return (sys_jiffies+music_tM_correction)/JIFFY_FREQ;
|
||||
}
|
||||
|
||||
public F64 tMBeat()
|
||||
{ //Time in music beats
|
||||
F64 result,cur_tM;
|
||||
PushFD;
|
||||
Cli;
|
||||
if (mp_cnt>1)
|
||||
while (LBts(&sys_semas[SYS_SEMA_TMBEAT],0))
|
||||
Pause;
|
||||
cur_tM=tM;
|
||||
result=music_last_tMBeat;
|
||||
if (music_tempo)
|
||||
result+=(cur_tM-music_last_tM)*music_tempo;
|
||||
music_last_tM=cur_tM;
|
||||
music_last_tMBeat=result;
|
||||
LBtr(&sys_semas[SYS_SEMA_TMBEAT],0);
|
||||
PopFD;
|
||||
return result;
|
||||
}
|
||||
|
||||
#help_index "Snd/Music"
|
||||
U8 *MusicSetOctave(U8 *st)
|
||||
{
|
||||
U8 ch=*st++;
|
||||
while ('0'<=ch<='9') {
|
||||
music_octave=ch-'0';
|
||||
ch=*st++;
|
||||
}
|
||||
return --st;
|
||||
}
|
||||
|
||||
U8 *MusicSetWaveform(U8 *st)
|
||||
{
|
||||
U8 ch=*st++;
|
||||
while (ch=='W') {
|
||||
ch=*st++;
|
||||
if ('0'<=ch<'0'+WF_NUM_WAVEFORMS) {
|
||||
music_waveform=ch-'0';
|
||||
ch=*st++;
|
||||
}
|
||||
}
|
||||
return --st;
|
||||
}
|
||||
|
||||
U8 *MusicSetMeter(U8 *st)
|
||||
{
|
||||
U8 ch=*st++;
|
||||
while (ch=='M') {
|
||||
ch=*st++;
|
||||
if ('0'<=ch<='9') {
|
||||
music_meter_top=ch-'0';
|
||||
ch=*st++;
|
||||
}
|
||||
if (ch=='/')
|
||||
ch=*st++;
|
||||
if ('0'<=ch<='9') {
|
||||
music_meter_bottom=ch-'0';
|
||||
ch=*st++;
|
||||
}
|
||||
}
|
||||
return --st;
|
||||
}
|
||||
|
||||
U8 *MusicSetNoteLen(U8 *st)
|
||||
{
|
||||
Bool cont=TRUE;
|
||||
do {
|
||||
switch (*st++) {
|
||||
case 'w': music_note_len=4.0; break;
|
||||
case 'h': music_note_len=2.0; break;
|
||||
case 'q': music_note_len=1.0; break;
|
||||
case 'e': music_note_len=0.5; break;
|
||||
case 's': music_note_len=0.25; break;
|
||||
case 't': music_note_len=2.0*music_note_len/3.0; break;
|
||||
case '.': music_note_len=1.5*music_note_len; break;
|
||||
default:
|
||||
st--;
|
||||
cont=FALSE;
|
||||
}
|
||||
} while (cont);
|
||||
return st;
|
||||
}
|
||||
|
||||
public U0 Play(U8 *st,U8 *words=NULL)
|
||||
/*
|
||||
Notes are entered with a capital letter.
|
||||
|
||||
Octaves are entered with a digit and
|
||||
stay set until changed.
|
||||
|
||||
Durations are entered with
|
||||
'w' whole note
|
||||
'h' half note
|
||||
'q' quarter note
|
||||
'e' eighth note
|
||||
't' sets to 2/3rds the current duration
|
||||
'.' sets to 1.5 times the current duration
|
||||
durations stay set until changed.
|
||||
|
||||
'(' tie, placed before the note to be extended
|
||||
|
||||
Accents are made with
|
||||
'!' *1.5
|
||||
'!!' *1.5`2
|
||||
|
||||
$LK,"music_waveform","MN:music_waveform"$ is set with
|
||||
"W1" for $LK,"WF_SQUARE","MN:WF_SQUARE"$
|
||||
"W2" for $LK,"WF_SINE","MN:WF_SINE"$
|
||||
"W3" for $LK,"WF_TRIANGLE","MN:WF_TRIANGLE"$
|
||||
"W4" for $LK,"WF_SAWTOOTH","MN:WF_SAWTOOTH"$
|
||||
"W5" for $LK,"WF_NOISE","MN:WF_NOISE"$
|
||||
|
||||
$LK,"music_meter_top","MN:music_meter_top"$,$LK,"music_meter_bottom","MN:music_meter_bottom"$ is set with
|
||||
"M3/4"
|
||||
"M4/4"
|
||||
etc.
|
||||
|
||||
Sharp and flat are done with '#' or 'b'.
|
||||
|
||||
The var music_stacatto_factor can
|
||||
be set to a range from 0.0 to 1.0.
|
||||
|
||||
The var music_amplitude can
|
||||
be set to a range from 0.0 to 1.0.
|
||||
|
||||
The var music_tempo is quarter-notes
|
||||
per second. It defaults to
|
||||
2.5 and gets faster when bigger.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
U8 *word,*last_st;
|
||||
I64 note,i=0,timeout_val,timeout_val2;
|
||||
Bool tie,old_preempt=Preempt(OFF);
|
||||
F64 f,d,a,on_jiffies,off_jiffies;
|
||||
music_play_note_num=0;
|
||||
while (*st) {
|
||||
timeout_val=sys_jiffies;
|
||||
a=music_amplitude;
|
||||
tie=FALSE;
|
||||
|
||||
do {
|
||||
last_st=st;
|
||||
if (*st=='!') {
|
||||
a*=1.5;
|
||||
st++;
|
||||
} else if (*st=='(') {
|
||||
tie=TRUE;
|
||||
st++;
|
||||
} else {
|
||||
st=MusicSetWaveform(st);
|
||||
st=MusicSetMeter(st);
|
||||
st=MusicSetOctave(st);
|
||||
st=MusicSetNoteLen(st);
|
||||
}
|
||||
} while (st!=last_st);
|
||||
|
||||
if (!*st) break;
|
||||
note=*st++-'A';
|
||||
if (note<7) {
|
||||
note=music_note_map[note];
|
||||
if (*st=='b') {
|
||||
note--;
|
||||
st++;
|
||||
} else if (*st=='#') {
|
||||
note++;
|
||||
st++;
|
||||
}
|
||||
f=Note2Freq(note,music_octave);
|
||||
} else
|
||||
f=0;
|
||||
if (words) {
|
||||
if (word=LstEntryPt(i++,words))
|
||||
if (StrCmp(word," "))
|
||||
"" word;
|
||||
}
|
||||
|
||||
d=JIFFY_FREQ*music_note_len/music_tempo;
|
||||
if (tie) {
|
||||
on_jiffies =d;
|
||||
off_jiffies =0;
|
||||
} else {
|
||||
on_jiffies =d*music_stacatto_factor;
|
||||
off_jiffies =d*(1.0-music_stacatto_factor);
|
||||
}
|
||||
timeout_val+=on_jiffies;
|
||||
timeout_val2=timeout_val+off_jiffies;
|
||||
|
||||
if (!music_mute)
|
||||
Snd(f,music_waveform,a);
|
||||
SleepUntil(timeout_val);
|
||||
music_tM_correction+=on_jiffies-ToI64(on_jiffies);
|
||||
|
||||
if (!music_mute)
|
||||
Snd(0,music_waveform,a);
|
||||
SleepUntil(timeout_val2);
|
||||
music_tM_correction+=off_jiffies-ToI64(off_jiffies);
|
||||
|
||||
music_play_note_num++;
|
||||
}
|
||||
Preempt(old_preempt);
|
||||
}
|
||||
|
||||
U0 MusicSettingsRst()
|
||||
{
|
||||
music_play_note_num=0;
|
||||
music_stacatto_factor=0.9;
|
||||
music_amplitude=1/1.5`2;
|
||||
music_tempo=2.5;
|
||||
music_octave=3;
|
||||
music_note_len=1.0;
|
||||
music_waveform=WF_SQUARE;
|
||||
music_meter_top=4;
|
||||
music_meter_bottom=4;
|
||||
snd_reverb_intensity=0.2;
|
||||
snd_reverb_delay=0.3;
|
||||
|
||||
PushFD;
|
||||
Cli;
|
||||
if (mp_cnt>1)
|
||||
while (LBts(&sys_semas[SYS_SEMA_TMBEAT],0))
|
||||
Pause;
|
||||
music_last_tM=tM;
|
||||
music_last_tMBeat=0.0;
|
||||
LBtr(&sys_semas[SYS_SEMA_TMBEAT],0);
|
||||
PopFD;
|
||||
}
|
||||
|
||||
MusicSettingsRst;
|
||||
|
||||
U0 CurSongTask()
|
||||
{
|
||||
if (!IsSysDeterministic)
|
||||
Preempt(ON);
|
||||
Fs->task_end_cb=&SndTaskEndCB;
|
||||
while (TRUE)
|
||||
Play(cur_song);
|
||||
}
|
||||
#help_index "Snd"
|
||||
@@ -0,0 +1,66 @@
|
||||
#help_index "Snd"
|
||||
|
||||
class CSndWaveCtrl
|
||||
{
|
||||
I64 sample_rate,sample_bits,channels;
|
||||
F64 freq_multiplier,amp_multiplier;
|
||||
F64 phase,last_y,last_dydt,next_y;
|
||||
};
|
||||
|
||||
I64 snd_obuf_num,snd_ibuf_num;
|
||||
|
||||
#define Sf_FILLING_OUT 0
|
||||
I64 snd_flags;
|
||||
|
||||
public U0 SndTaskEndCB()
|
||||
//This will turn-off snd when a task gets killed.
|
||||
{
|
||||
Snd(0);
|
||||
Exit;
|
||||
}
|
||||
|
||||
|
||||
class CSndData
|
||||
{
|
||||
CSndData *next,*last;
|
||||
U8 waveform,pad[7];
|
||||
F64 amp; //0.0-1.0
|
||||
F64 freq; //Hz
|
||||
F64 time_stamp;
|
||||
} snd_record_root;
|
||||
|
||||
U0 SndRecord(F64 freq,I64 waveform,F64 amp)
|
||||
{
|
||||
CSndData *d;
|
||||
d=ACAlloc(sizeof(CSndData));
|
||||
d->freq=freq;
|
||||
d->time_stamp=tT;
|
||||
d->waveform=waveform;
|
||||
d->amp=amp;
|
||||
QueIns(d,snd_record_root.last);
|
||||
}
|
||||
|
||||
U0 CtrlAltV(I64 sc)
|
||||
{
|
||||
if (sc&SCF_SHIFT)
|
||||
snd_vol/=1.5;
|
||||
else
|
||||
snd_vol*=1.5;
|
||||
}
|
||||
SetCtrlAltLetCB('V',&CtrlAltV,"Sys/Snd Volume +/-");
|
||||
|
||||
U0 SndInit()
|
||||
{
|
||||
QueInit(&snd_record_root);
|
||||
snd_record_root.freq=0;
|
||||
snd_record_root.time_stamp=tT;
|
||||
fp_snd_record=&SndRecord;
|
||||
}
|
||||
|
||||
SndInit;
|
||||
|
||||
#include "MathAudio"
|
||||
#include "Music"
|
||||
#include "SndEffects"
|
||||
#include "SndFile"
|
||||
#help_index ""
|
||||
@@ -0,0 +1,68 @@
|
||||
#define SE_NOISE 0
|
||||
#define SE_SWEEP 1
|
||||
|
||||
class CSoundEffectFrame
|
||||
{
|
||||
I32 type,waveform;
|
||||
F64 duration,freq1,freq2;
|
||||
};
|
||||
|
||||
U0 SoundEffectEndTaskCB()
|
||||
{
|
||||
Free(NamedFramePtr("CSoundEffectFrame"));
|
||||
music_mute--;
|
||||
SndTaskEndCB;
|
||||
}
|
||||
|
||||
U0 SoundEffectTask(CSoundEffectFrame *ns)
|
||||
{
|
||||
I64 i;
|
||||
F64 f,t0=tS,t,timeout=t0+ns->duration;
|
||||
NamedFramePtrAdd("CSoundEffectFrame",ns);
|
||||
Fs->task_end_cb=&SoundEffectEndTaskCB;
|
||||
switch (ns->type) {
|
||||
case SE_NOISE:
|
||||
i=MaxI64(ns->freq2-ns->freq1,1);
|
||||
while (tS<timeout)
|
||||
if (f=RandU16%i+ns->freq1) {
|
||||
Snd(f,ns->waveform);
|
||||
Sleep(MaxI64(3000/f,1));
|
||||
} else
|
||||
break;
|
||||
break;
|
||||
case SE_SWEEP:
|
||||
while (tS<timeout) {
|
||||
t=(tS-t0)/ns->duration;
|
||||
if (f=(1.0-t)*ns->freq1+t*ns->freq2) {
|
||||
Snd(f,ns->waveform);
|
||||
Sleep(MaxI64(3000/f,1));
|
||||
} else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public CTask *Noise(I64 mS,F64 min_freq,F64 max_freq,I64 waveform=WF_NOISE)
|
||||
{
|
||||
CSoundEffectFrame *ns=MAlloc(sizeof(CSoundEffectFrame));
|
||||
ns->type=SE_NOISE;
|
||||
ns->waveform=waveform;
|
||||
ns->duration=mS/1000.0;
|
||||
ns->freq1=min_freq;
|
||||
ns->freq2=max_freq;
|
||||
music_mute++;
|
||||
return Spawn(&SoundEffectTask,ns,"Noise",Fs);
|
||||
}
|
||||
|
||||
public CTask *Sweep(I64 mS,F64 freq1,F64 freq2,I64 waveform=WF_SINE)
|
||||
{
|
||||
CSoundEffectFrame *ns=MAlloc(sizeof(CSoundEffectFrame));
|
||||
ns->type=SE_SWEEP;
|
||||
ns->waveform=waveform;
|
||||
ns->duration=mS/1000.0;
|
||||
ns->freq1=freq1;
|
||||
ns->freq2=freq2;
|
||||
music_mute++;
|
||||
return Spawn(&SoundEffectTask,ns,"Noise",Fs);
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
#help_index "Snd/Snd Files"
|
||||
#define SNDFILE_SAMPLE_RATE 8000
|
||||
//Header for a ".SND" file
|
||||
class CFileSND
|
||||
{ //big endian
|
||||
U32 signature; //0x646e732e
|
||||
U32 offset; //24
|
||||
U32 data_size;
|
||||
U32 coding; //3=16bit uncompressed
|
||||
U32 sample_rate; //Hz
|
||||
U32 channels; //1=mono
|
||||
I16 body[1];
|
||||
};
|
||||
|
||||
//This is a windows media constraint.
|
||||
#define MAX_SND_FILE_DATA 0x7FF00
|
||||
|
||||
|
||||
public I64 SndFileCreate(U8 *base_filename,F64 normalized_vol=1.0,F64 averaging=0.0,I64 waveform=WF_NULL,
|
||||
F64 reverb_delay=0,F64 reverb_intensity=0)
|
||||
//Use "snd_record" flag to start or stop
|
||||
//recording, then call this routine.
|
||||
|
||||
//Averaging should be a num from 0.0 to 0.999.
|
||||
//Vol should be from 0.0 to 1.0.
|
||||
//If waveform is $LK,"WF_NULL","MN:WF_NULL"$, the original passed to $LK,"Snd","MN:Snd"$() will be used.
|
||||
|
||||
//Set reverb_delay to like 0.3 sec and reverb_intensity to like 0.4.
|
||||
|
||||
{
|
||||
I64 i,k,cnt,cnt2,level,file_num;
|
||||
F64 avg,dt;
|
||||
CFileSND *s;
|
||||
CSndWaveCtrl *swc=SndWaveCtrlNew(SNDFILE_SAMPLE_RATE,16,1);
|
||||
CSndData *d,*d1;
|
||||
U8 *name,*name2;
|
||||
|
||||
snd_record=FALSE;
|
||||
|
||||
dt=snd_record_root.last->time_stamp-snd_record_root.next->time_stamp;
|
||||
if (!dt) return 0;
|
||||
cnt=dt*SNDFILE_SAMPLE_RATE;
|
||||
cnt++; //terminator
|
||||
|
||||
name=StrNew(base_filename);
|
||||
FileExtRem(name);
|
||||
|
||||
s=CAlloc(offset(CFileSND.body)+cnt*sizeof(I16));
|
||||
s->signature=0x646e732e;
|
||||
s->offset=EndianU32(offset(CFileSND.body));
|
||||
s->coding=EndianU32(3);
|
||||
s->sample_rate=EndianU32(SNDFILE_SAMPLE_RATE);
|
||||
s->channels=EndianU32(1);
|
||||
|
||||
d=snd_record_root.next;
|
||||
k=0;
|
||||
while (d->next!=&snd_record_root) {
|
||||
d1=d->next;
|
||||
dt=d1->time_stamp-d->time_stamp;
|
||||
cnt2=dt*SNDFILE_SAMPLE_RATE;
|
||||
SndWaveAddBuf(swc,&s->body[k],cnt2,d->freq,waveform ?waveform:d->waveform,d->amp*normalized_vol);
|
||||
k+=cnt2;
|
||||
QueRem(d);
|
||||
Free(d);
|
||||
d=d1;
|
||||
}
|
||||
|
||||
//Average
|
||||
if (averaging) {
|
||||
avg=0;
|
||||
for (i=0;i<cnt-1;i++)
|
||||
s->body[i]=avg=LowPass1(averaging,avg,s->body[i],1.0);
|
||||
}
|
||||
|
||||
//reverb
|
||||
if (reverb_intensity) {
|
||||
if (dt=reverb_delay*SNDFILE_SAMPLE_RATE)
|
||||
for (i=dt;i<cnt;i++)
|
||||
s->body[i]+=reverb_intensity*s->body[i-dt];
|
||||
}
|
||||
|
||||
//Get rid of D.C. component
|
||||
for (k=0;k<3;k++) {
|
||||
level=0;
|
||||
for (i=0;i<cnt-1;i++)
|
||||
level+=s->body[i];
|
||||
level/=cnt-1;
|
||||
for (i=0;i<cnt-1;i++)
|
||||
s->body[i]=LimitI64(s->body[i]-level,MIN_I16,MAX_I16);
|
||||
}
|
||||
|
||||
for (i=0;i<cnt-1;i++)
|
||||
s->body[i]=EndianU16(s->body[i]);
|
||||
|
||||
s->body[cnt-1]=0;
|
||||
|
||||
d=snd_record_root.next;
|
||||
while (d!=&snd_record_root) {
|
||||
d1=d->next;
|
||||
QueRem(d);
|
||||
Free(d);
|
||||
d=d1;
|
||||
}
|
||||
|
||||
name2=MAlloc(StrLen(name)+3+1+3+1);
|
||||
cnt2=cnt;
|
||||
file_num=0;
|
||||
while (cnt2>0) {
|
||||
i=cnt2;
|
||||
if (i>MAX_SND_FILE_DATA)
|
||||
i=MAX_SND_FILE_DATA;
|
||||
s->data_size=EndianU32(i*sizeof(I16));
|
||||
MemCpy(s->body,&s->body[file_num*MAX_SND_FILE_DATA],i*sizeof(I16));
|
||||
SPrintF(name2,"%s%03d.SND",name,file_num++);
|
||||
FileWrite(name2,s,offset(CFileSND.body)+i*sizeof(I16));
|
||||
cnt2-=i;
|
||||
}
|
||||
Free(s);
|
||||
Free(name);
|
||||
Free(name2);
|
||||
|
||||
SndWaveCtrlDel(swc);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public U0 SndFileWrite(U8 *filename,SND_IN_CONTAINER *buf,I64 cnt)
|
||||
{
|
||||
CFileSND *s;
|
||||
I64 i,j,l=SND_SAMPLE_RATE/SNDFILE_SAMPLE_RATE;
|
||||
F64 level,a1,a2;
|
||||
|
||||
cnt/=l;
|
||||
s=CAlloc(offset(CFileSND.body)+cnt*sizeof(I16));
|
||||
s->signature=0x646e732e;
|
||||
s->offset=EndianU32(offset(CFileSND.body));
|
||||
s->coding=EndianU32(3);
|
||||
s->sample_rate=EndianU32(SNDFILE_SAMPLE_RATE);
|
||||
s->channels=EndianU32(1);
|
||||
s->data_size=EndianU32(cnt*sizeof(I16));
|
||||
|
||||
//Get rid of D.C. component
|
||||
j=cnt*l;
|
||||
level=0;
|
||||
for (i=0;i<j;i++)
|
||||
level+=buf[i];
|
||||
level/=j;
|
||||
for (i=0;i<j;i++)
|
||||
buf[i]=LimitI64(buf[i]-level,MIN_I16,MAX_I16);
|
||||
|
||||
//2nd order low pass filter. Time constant set by nyquest freq.
|
||||
a1=1.0/SND_SAMPLE_RATE/(2.0/SNDFILE_SAMPLE_RATE+1.0/SND_SAMPLE_RATE);
|
||||
a2=1.0-a1;
|
||||
for (i=1;i<j;i++)
|
||||
buf[i]=a1*buf[i]+a2*buf[i-1];
|
||||
for (i=1;i<j;i++)
|
||||
buf[i]=a1*buf[i]+a2*buf[i-1];
|
||||
|
||||
j=0;
|
||||
for (i=0;i<cnt;i++) {
|
||||
s->body[i]=EndianU16(buf[j]);
|
||||
j+=l;
|
||||
}
|
||||
FileWrite(filename,s,offset(CFileSND.body)+cnt*sizeof(I16));
|
||||
Free(s);
|
||||
}
|
||||
|
||||
public U0 SndFileView(U8 *name,Bool zoom=FALSE)
|
||||
{
|
||||
I64 i,start,end,w=Fs->win_pixel_width,h=Fs->win_pixel_height;
|
||||
F64 x_scale,y_scale;
|
||||
CFileSND *s=FileRead(name);
|
||||
if (s) {
|
||||
s->data_size=EndianU32(s->data_size)/sizeof(I16);
|
||||
for (i=0;i<s->data_size;i++)
|
||||
s->body[i]=EndianU16(s->body[i]);
|
||||
start=1;
|
||||
end=s->data_size;
|
||||
if (zoom) {
|
||||
for (i=1;i<end;i++)
|
||||
if (s->body[i]!=s->body[i-1]) {
|
||||
start=i;
|
||||
break;
|
||||
}
|
||||
if (s->data_size-start>w)
|
||||
end=start+w;
|
||||
}
|
||||
"$$CL$$";
|
||||
DCFill;
|
||||
CDC *dc=DCAlias;
|
||||
dc->color=GREEN;
|
||||
x_scale=ToF64(w)/(end-start+1);
|
||||
y_scale=ToF64(h)/MAX_U16;
|
||||
for (i=start;i<end;i++)
|
||||
GrLine(dc,x_scale*(i-start),y_scale*(s->body[i]+MAX_I16),
|
||||
x_scale*(i-start-1),y_scale*(s->body[i-1]+MAX_I16));
|
||||
Free(s);
|
||||
PressAKey;
|
||||
DCFill;
|
||||
DCDel(dc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CFileSND *snd_play_snd_file=NULL;
|
||||
I64 snd_play_start_buf_num,snd_play_samples_per_sample;
|
||||
Bool snd_play_done=TRUE,snd_play_single_done;
|
||||
U0 (*fp_snd_play_task_end_cb)()=NULL;
|
||||
U0 (*fp_snd_play_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
|
||||
|
||||
CFileSND *SndFileLoad(U8 *name)
|
||||
{
|
||||
I64 i;
|
||||
CFileSND *s=FileRead(name);
|
||||
if (s) {
|
||||
s->data_size=EndianU32(s->data_size)/sizeof(I16);
|
||||
for (i=0;i<s->data_size;i++)
|
||||
s->body[i]=EndianU16(s->body[i]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
U0 SndFileFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
|
||||
{
|
||||
I64 i,j,k,m;
|
||||
if (snd_play_done) return;
|
||||
buf_num-=snd_play_start_buf_num;
|
||||
j=buf_num*(SND_BUF_LEN/SND_OCHANNELS*SNDFILE_SAMPLE_RATE/SND_SAMPLE_RATE);
|
||||
i=j%snd_play_snd_file->data_size;
|
||||
k=j%snd_play_samples_per_sample;
|
||||
j=0;
|
||||
while (j<SND_BUF_LEN) {
|
||||
m=snd_vol*snd_play_snd_file->body[i++]<<16;
|
||||
while (j<SND_BUF_LEN) {
|
||||
buf[j++]=m;
|
||||
buf[j++]=m;
|
||||
if (++k==snd_play_samples_per_sample)
|
||||
break;
|
||||
}
|
||||
if (i>=snd_play_snd_file->data_size) {
|
||||
while (j<SND_BUF_LEN) {
|
||||
buf[j++]=0;
|
||||
buf[j++]=0;
|
||||
}
|
||||
snd_play_done=TRUE;
|
||||
break;
|
||||
}
|
||||
k=0;
|
||||
}
|
||||
}
|
||||
|
||||
U0 SndFilePlayTaskEndCB()
|
||||
{
|
||||
snd_play_done=TRUE;
|
||||
fp_snd_fill_buf=fp_snd_play_old_fill_buf;
|
||||
if (fp_snd_play_task_end_cb)
|
||||
(*fp_snd_play_task_end_cb)();
|
||||
else
|
||||
Exit;
|
||||
}
|
||||
|
||||
//See $LK-A,"::/TempleOS/Apps/MusicOrgan/Help.TXT"$
|
||||
//See $LK,"SndFileCreate","MN:SndFileCreate"$().
|
||||
public U0 SndFilePlay(U8 *snz_filename)
|
||||
{
|
||||
if (snd_play_done) {
|
||||
TaskInitExt;
|
||||
snd_play_snd_file=SndFileLoad(snz_filename);
|
||||
snd_play_samples_per_sample=SND_SAMPLE_RATE/SNDFILE_SAMPLE_RATE;
|
||||
fp_snd_play_task_end_cb=Fs->task_end_cb;
|
||||
Fs->task_end_cb=&SndFilePlayTaskEndCB;
|
||||
snd_play_start_buf_num=snd_obuf_num;
|
||||
snd_play_done=FALSE;
|
||||
fp_snd_play_old_fill_buf=fp_snd_fill_buf;
|
||||
fp_snd_fill_buf=&SndFileFillBuf;
|
||||
try {
|
||||
while (!snd_play_done)
|
||||
Sleep(1);
|
||||
} catch {
|
||||
snd_play_done=TRUE;
|
||||
fp_snd_fill_buf=fp_snd_play_old_fill_buf;
|
||||
Fs->task_end_cb=fp_snd_play_task_end_cb;
|
||||
Free(snd_play_snd_file);
|
||||
snd_play_snd_file=NULL;
|
||||
}
|
||||
fp_snd_fill_buf=fp_snd_play_old_fill_buf;
|
||||
Fs->task_end_cb=fp_snd_play_task_end_cb;
|
||||
Free(snd_play_snd_file);
|
||||
snd_play_snd_file=NULL;
|
||||
}
|
||||
snd_play_single_done=TRUE;
|
||||
}
|
||||
|
||||
public U0 SndFilePlaySeq(U8 *snz_filename,I64 num)
|
||||
{ //This has gaps between files. I might fix it someday. You fix it;-)
|
||||
I64 i;
|
||||
Bool old_preempt=Preempt(OFF),old_idle;
|
||||
U8 *fname=StrNew(snz_filename),*fname2;
|
||||
FileExtRem(fname);
|
||||
old_idle=LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
for (i=0;i<num;i++) {
|
||||
fname2=MSPrintF("%s%04d.SNZ",fname,i);
|
||||
while (!snd_play_done)
|
||||
Yield;
|
||||
snd_play_single_done=FALSE;
|
||||
Spawn(&SndFilePlay,fname2,"Play .SNZ",Fs);
|
||||
while (!snd_play_single_done)
|
||||
Yield;
|
||||
Free(fname2);
|
||||
}
|
||||
old_idle=LBEqu(&Fs->task_flags,TASKf_IDLE,old_idle);
|
||||
Free(fname);
|
||||
Preempt(old_preempt);
|
||||
}
|
||||
|
||||
#help_index ""
|
||||
Reference in new issue
Block a user