SparrowOSTS_121127.ISO

This commit is contained in:
Terry A. Davis authored and minexew committed 2018-09-08 21:45:28 +02:00
1 parent 0e9364ff4c
commit e57428affb
1218 files changed
+247142 -165507

No files matched your search

+610
View File
@@ -0,0 +1,610 @@
#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_LIST 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_LIST_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
DefineListLoad("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;
};
class CHDAudioCtrl
{
U8 *bar;
I64 cad;
U32 *corb;
I64 *rirb;
CHDBufDesc *ostr0_bdl,*istr0_bdl;
SND_OUT_CONTAINER *ostr0_buf[2];
SND_IN_CONTAINER *istr0_buf[2];
CTask *task;
I64 waveform;
F64 freq,amp;
CSndWaveCtrl *sc;
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);
/* uncached heap
result+=MSize2(_hda->corb)+MSize(_hda->rirb);
result+=MSize2(_hda->ostr0_bdl);
result+=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_LIST_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)
{
SndWaveFillBuf(_hda->sc,buf,SND_BUF_LEN/SND_OCHANNELS,_hda->freq,_hda->waveform,snd_vol*_hda->amp);
}
U0 HDAudioTaskEndCB()
{
HDStop(FALSE,TRUE);
fp_snd=NULL;
SndWaveCtrlDel(_hda->sc);
_hda->sc=NULL;
Exit;
}
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 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;
_hda->sc=SndWaveCtrlNew;
_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->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;
}
HDAudioInit(0,27,0);
//$BK,1$Run $LK,"::/SparrowOS/Adam/Snd/HDCfg.CPP.Z","FI:::/SparrowOS/Adam/Snd/HDCfg.CPP.Z"$.$BK,0$
#help_index ""
+638
View File
@@ -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_list[MAX_CONNECTS];
U8 gain_list[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_list[0]=0x7F;
MemSet(tempm->gain_list+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_list[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_list[i]) &&
(tempm1=FindMassByNID(k)) ) {
temps=PlaceSpring(tempm,tempm1);
switch (tempm->type) {
case AWT_MIXER:
if (!(tempm->gain_list[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 HDCfgConnectList(MyMass *tempm,I64 cad,I64 nid)
{
I64 i,j,connection_list_len;
j=HDWriteCORBSync(cad,nid,VERB_GET_PARAM+P_CONNECT_LIST_LEN);
connection_list_len=j&127;
if (j&128) { //Long form?
for (i=0;i<connection_list_len;i+=2) {
j=HDWriteCORBSync(cad,nid,VERB_GET_CONNECT_LIST+i);
tempm->connect_list[tempm->num_connects++]=j.u16[0];
if (i+1<connection_list_len)
tempm->connect_list[tempm->num_connects++]=j.u16[1];
}
} else {
for (i=0;i<connection_list_len;i+=4) {
j=HDWriteCORBSync(cad,nid,VERB_GET_CONNECT_LIST+i);
tempm->connect_list[tempm->num_connects++]=j.u8[0];
if (i+1<connection_list_len)
tempm->connect_list[tempm->num_connects++]=j.u8[1];
if (i+2<connection_list_len)
tempm->connect_list[tempm->num_connects++]=j.u8[2];
if (i+3<connection_list_len)
tempm->connect_list[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))
HDCfgConnectList(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 List, ";
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 List:$$FG$$\n";
for (i=0;i<tempm->num_connects;i++)
"%02X,",tempm->connect_list[i];
NewLine;
"\n$$FG,RED$$Gain List:$$FG$$\n";
for (i=0;i<tempm->num_connects;i++)
"%02X,",tempm->gain_list[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_list,0x80,sizeof(U8)*MAX_CONNECTS);
tempm_in->gain_list[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_list[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,\"::/SparrowOS/Adam/Snd/HDCfg.CPP.Z\",\"FI:::/SparrowOS/Adam/Snd/HDCfg.CPP.Z\"$$\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 List:");
for (i=0;i<tempm->num_connects;i++) {
if (i==tempm->cur_connect)
DocPutS(doc,"*");
DocPrintF(doc,"0x%02X ",tempm->connect_list[i]);
}
DocPutS(doc,"\n");
if (tempm->type==AWT_MIXER) {
DocPutS(doc," //Gain List:");
for (i=0;i<tempm->num_connects;i++)
DocPrintF(doc,"0x%02X ",tempm->gain_list[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_list[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(,CH_NEW_LINE);"
" 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 CH_NEW_LINE:
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.CPP.Z\" in your start-up scripts.$$BK,0$$\n";
}
HDCfg;
+239
View File
@@ -0,0 +1,239 @@
#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 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 1.0-2.0*(t%period/period);
else
return -1.0-2.0*(t%period/period);
} 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 *sc=CAlloc(sizeof(CSndWaveCtrl),mem_task);
sc->sample_rate=sample_rate;
sc->sample_bits=sample_bits;
sc->channels=channels;
sc->last_dydt=1.0;
return sc;
}
public U0 SndWaveCtrlDel(CSndWaveCtrl *sc)
{
Free(sc);
}
public U0 SndWaveFillBuf(CSndWaveCtrl *sc,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 (!sc) return;
if (!_freq) {
MemSet(buf,0,num_samples*sc->channels*(sc->sample_bits>16 ? sizeof(I32):sizeof(I16)));
sc->last_y=sc->phase=0;
sc->last_dydt=1.0;
} else {
phase=sc->phase;
i=0;
amp=Min(MAX_I32,MAX_I32*_amp);
f=2*ã/sc->sample_rate*_freq;
switch (_waveform) {
case WF_NOISE:
a=2.0/ã*amp;
break;
case WF_SAWTOOTH:
a=amp/ã;
break;
case WF_SINE:
phase=SinPhaseCont(sc->last_y,sc->last_dydt,amp,0.0);
break;
}
while (phase<0)
phase+=2*ã;
while (phase>=2*ã)
phase-=2*ã;
num_samples*=sc->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>=ã) {
sc->last_y=sc->next_y;
sc->next_y=-amp*Sign(sc->last_y)+.00001;
phase-=ã;
}
j=(sc->last_y*(ã-phase)+sc->next_y*phase)/ã;
break;
case WF_SAWTOOTH:
j=a*(phase-ã);
break;
case WF_NOISE:
if (phase<ã) {
if (phase<f) {
sc->last_y=sc->next_y;
sc->next_y=a*RandI16/MAX_U16;
}
j=sc->last_y*(ã-phase)+sc->next_y*phase;
} else {
if (phase-ã<f) {
sc->last_y=sc->next_y;
sc->next_y=a*RandI16/MAX_U16;
}
j=sc->last_y*(2.0*ã-phase)+sc->next_y*(phase-ã);
}
break;
}
//left channel
k=j*_left;
if (sc->sample_bits==16) {
k>>=16;
buf(I16 *)[i++]=k;
} else {
if (sc->sample_bits==24)
k&=0xFFFFFF00;
buf(I32 *)[i++]=k;
}
//right channel
if (sc->channels==2) {
k=j*_right;
if (sc->sample_bits==16) {
k>>=16;
buf(I16 *)[i++]=k;
} else {
if (sc->sample_bits==24)
k&=0xFFFFFF00;
buf(I32 *)[i++]=k;
}
}
phase+=f;
while (phase>=2*ã)
phase-=2*ã;
}
if (_waveform==WF_SINE) {
sc->last_y=amp*Sin(phase);
sc->last_dydt=Cos(phase);
}
sc->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"
+260
View File
@@ -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=ListEntryPt(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"
+64
View File
@@ -0,0 +1,64 @@
#help_index "Snd"
class CSndWaveCtrl
{
I64 sample_rate,sample_bits,channels;
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=tNP;
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=tNP;
fp_snd_record=&SndRecord;
}
SndInit;
#include "MathAudio"
#include "Music"
#include "SndEffects"
#help_index ""
+68
View File
@@ -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 U0 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++;
Spawn(&SoundEffectTask,ns,"Noise",Fs);
}
public U0 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++;
Spawn(&SoundEffectTask,ns,"Noise",Fs);
}
+316
View File
@@ -0,0 +1,316 @@
#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;
F64 avg,dt;
CFileSND *s;
CSndWaveCtrl *sc=SndWaveCtrlNew(SNDFILE_SAMPLE_RATE,16,1);
CSndData *d,*d1;
U8 *name,*name2;
I64 file_num;
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;
SndWaveFillBuf(sc,&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(sc);
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,"::/SparrowOS/Apps/MusicOrgan/Help.TXT.Z","FI:::/SparrowOS/Apps/MusicOrgan/Help.TXT.Z"$
//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 ""