Add temporary Sound dir and modified driver files.

Sources:
AC97: https://git.checksum.fail/alec/TOSamp
HDAudio0: https://git.checksum.fail/alec/templenes
HDAudio1: https://github.com/dancoyle21/sup1hdaudio (fork of alec's sup1hdaudio repo)
This commit is contained in:
TomAwezome 2022-12-23 22:41:22 -05:00
parent b14b485716
commit b7821cbc95
21 changed files with 4530 additions and 0 deletions

244
src/Home/Sound/AC97/AC97.ZC Normal file
View file

@ -0,0 +1,244 @@
#define INT_LAST_VALID_ENTRY 1 << 2
#define INT_IOC 1 << 3
#define INT_FIFO_ERR 1 << 4
#define BDL_BUF_SIZE 2044
#define PCM_BUF_SIZE 2048
#define MAX_BDLS 32
#define PCM_IN 0
#define PCM_OUT 1
#define MIC_IN 2
// Native Audio Mixer registers (all U16)
#define RESET 0x00 // Reset Register
#define MASTER_VOL 0x02 // Set Master Output Volume
#define MIC_VOL 0x0E // Set Microphone Volume
#define PCM_VOL 0x18 // Set Output Volume of PCM patterns
#define REC_SLC 0x1A // Select Input Device
#define REC_GAIN 0x1C // Set Input Gain
#define MIC_GAIN 0x1E // Set Gain of Microphone
#define EXT_ID 0x28 // Supported extended functions
#define EXT_CTRL 0x2A // Enabling extended functions
#define EXT_FRONT_RATE 0x2C // Sample rate of front speaker
// Native Audio Bus Master registers
#define PCM_INPUT_REG_BOX\
0x00 // NABM register box for PCM IN (sizeof NABM register box)
#define PCM_OUTPUT_REG_BOX\
0x10 // NABM register box for PCM OUT (sizeof NABM register box)
#define MIC_INPUT_REG_BOX\
0x20 // NABM register box for Microphone (sizeof NABM register box)
#define GLOBAL_CTL 0x2C // Global Control Register (U32)
#define GLOBAL_STS 0x30 // Global Status Register (U32)
// NABM register box registers
#define BUFFER_DSC_ADDR 0x00 // Physical Address of Buffer Descriptor List (U32)
#define CUR_ENTRY_VAL\
0x04 // Number of Actual Processed Buffer Descriptor Entry (U8)
#define LAST_VALID_ENTRY 0x05 // Number of all Descriptor Entries (U8)
#define TRANSFER_STS 0x06 // Status of Transferring Data (U16)
#define CUR_IDX_PROC_SAMPLES\
0x08 // Number of Transferred Samples in Actual Processed Entry (U16)
#define PRCSD_ENTRY 0x0A // Number of Actual Processed Buffer Entry (U8)
#define BUFFER_CNT\
0x0B // Most Important Register for controlling Transfers (U8)
class @ac97_bdl_entry
{
U32 addr;
U16 length; // length - 1
U16 flags;
};
class @ac97_bdl
{
@ac97_bdl_entry entries[32];
};
class @ac97
{
@pci_info pci;
@ac97_bdl *bdl[3];
U16 nam;
U16 nabm;
};
@ac97 AC97;
#define AUDIO_MAX_STREAMS 16
#define AUDIO_OUTPUT_BUFFER_SIZE 1024
#define AUDIO_STREAM_FIFO_SIZE 1048576 * 16
#define AUDIO_STREAM_TYPE_INPUT 0
#define AUDIO_STREAM_TYPE_OUTPUT 1
class @audio_stream
{
CFifoI64 * data;
};
class @audio
{
@audio_stream output[AUDIO_MAX_STREAMS];
I64 output_frames[AUDIO_MAX_STREAMS];
};
@audio Audio;
U0 @audio_init()
{
I64 i = 0;
for (i = 0; i < AUDIO_MAX_STREAMS; i++)
Audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE, sys_task);
}
@audio_init;
I64 @audio_get_available_output_stream()
{
I64 stream = 0;
while (FifoI64Count(Audio.output[stream].data))
stream++;
if (stream > AUDIO_MAX_STREAMS - 1)
return -1;
return stream;
}
I64 @audio_play_sfx(U32 *data, I64 length)
{
I64 i;
I64 stream = @audio_get_available_output_stream;
if (stream < 0)
return stream;
for (i = 0; i < length; i++)
FifoI64Ins(Audio.output[stream].data, data[i]);
return stream;
}
U0 @ac97_mix_output(U32 *buf, I64 length = NULL)
{
I64 i;
I64 j;
I64 acc_sample_L = 0;
I64 acc_sample_R = 0;
I64 acc_streams = 0;
U32 sample;
if (!length)
length = AUDIO_OUTPUT_BUFFER_SIZE;
for (i = 0; i < length / 4; i++)
{
acc_sample_L = 0;
acc_sample_R = 0;
acc_streams = 0;
for (j = 0; j < AUDIO_MAX_STREAMS; j++)
{
if (FifoI64Count(Audio.output[j].data))
{
FifoI64Remove(Audio.output[j].data, &sample);
Audio.output_frames[j]++;
acc_streams++;
acc_sample_L += sample.u16[0];
acc_sample_R += sample.u16[1];
}
}
buf[i].i16[0] = ToI64(acc_sample_L / Sqrt(acc_streams));
buf[i].i16[1] = ToI64(acc_sample_R / Sqrt(acc_streams));
}
}
U0 @ac97_fill_buffer()
{
I64 idx = InU8(AC97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY);
U32 *buf = AC97.bdl[PCM_OUT]->entries[idx].addr;
@ac97_mix_output(buf, BDL_BUF_SIZE);
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx);
}
U0 @ac97_process_audio()
{
U16 status = InU16(AC97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS);
if (status & INT_IOC)
{
@ac97_fill_buffer;
OutU16(AC97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C);
}
}
I64 @ac97_init()
{
I64 i;
I64 j;
// Scan for device
j = PCIClassFind(0x040100, 0);
if (j < 0)
{
device_not_found: SysLog("\n[AC'97] Device not found\n");
return -1;
}
@get_pci_info(j, &AC97.pci);
if (AC97.pci.vendor_id != 0x8086 || AC97.pci.device_id != 0x2415)
goto device_not_found;
AC97.nam = AC97.pci.bar[0] &0xFFFFFF00;
AC97.nabm = AC97.pci.bar[1] &0xFFFFFF00;
// Enable port IO, disable MMIO
PCIWriteU8(j.u8[2], j.u8[1], j.u8[0], 0x4, 5);
OutU32(AC97.nabm + GLOBAL_CTL, 0x03);
OutU16(AC97.nam + RESET, 0xFFFF);
// Set PCM Output to Max volume
OutU16(AC97.nam + PCM_VOL, 0x0000);
// Allocate Buffer Descriptor Lists
AC97.bdl[PCM_IN] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
AC97.bdl[PCM_OUT] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
AC97.bdl[MIC_IN] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
for (i = 0; i < MAX_BDLS; i++)
{
AC97.bdl[PCM_OUT]->entries[i].addr =
CAllocAligned(PCM_BUF_SIZE, 4096, Fs->code_heap);
AC97.bdl[PCM_OUT]->entries[i].length = BDL_BUF_SIZE / 2;
AC97.bdl[PCM_OUT]->entries[i].flags = 1 << 15;
}
// Set addresses of Buffer Descriptor Lists
// OutU32(AC97.nabm + PCM_INPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[PCM_IN]);
OutU32(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[PCM_OUT]);
// OutU32(AC97.nabm + MIC_INPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[MIC_IN]);
// Set Master Volume
OutU16(AC97.nam + MASTER_VOL, 0x0F0F);
// Stop playing sound
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 0);
// Fill one buffers
@ac97_fill_buffer;
// Enable interrupt handler
//@pci_register_int_handler(&@ac97_int_handler);
// Start playing sound
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 1);
return 0;
}
U0 @ac97_task()
{
while (1)
{
@ac97_process_audio;
Sleep(1);
}
}
@ac97_init;
Spawn(&@ac97_task,, "AC97 Task", 1);

View file

@ -0,0 +1,89 @@
#define PCI_INTH_MAX 16
U64 @pci_int_handler[PCI_INTH_MAX];
class @pci_info {
U16 vendor_id;
U16 device_id;
U16 command;
U16 status;
U32 _class;
U32 bar[6];
U32 cap_pointer;
};
class @pci_cap {
U8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
U8 cap_next; /* Generic PCI field: next ptr. */
U8 cap_len; /* Generic PCI field: capability length */
U8 cfg_type; /* Identifies the structure. */
U8 bar; /* Where to find it. */
U8 padding[3]; /* Pad to full dword. */
U32 offset; /* Offset within bar. */
U32 length; /* Length of the structure, in bytes. */
};
U0 @get_pci_info(I64 i, @pci_info *pci) {
I64 j;
pci->vendor_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) & 0xFFFF;
pci->device_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) >> 16;
pci->command = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) & 0xFFFF;
pci->status = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) >> 16;
pci->_class = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x8) >> 24;
for (j = 0; j < 6; j++)
pci->bar[j] = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x10 + (0x04 * j));
}
U0 @get_pci_cap(I64 i, @pci_cap *cap, I64 idx) {
I64 base = 0x40 + (idx * 16);
U32 u32;
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base);
cap->cap_vndr = u32.u8[0];
cap->cap_next = u32.u8[1];
cap->cap_len = u32.u8[2];
cap->cfg_type = u32.u8[3];
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x04);
cap->bar = u32.u8[0];
cap->offset = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x08);
cap->length = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x0c);
}
U0 @pci_reroute_interrupts(I64 base, I64 cpu) {
I64 i;
U8 *da = dev.uncached_alias + IOAPIC_REG;
U32 *_d = dev.uncached_alias + IOAPIC_DATA;
for (i = 0; i < 4; i++) {
*da = IOREDTAB + i * 2 + 1;
*_d = dev.mp_apic_ids[cpu] << 24;
*da = IOREDTAB + i * 2;
*_d = 0x4000 + base + i;
}
}
I64 @pci_register_int_handler(U64 handler) {
if (!handler)
return -1;
I64 i = 0;
while (@pci_int_handler[i])
i++;
if (i > PCI_INTH_MAX - 1)
return -1;
@pci_int_handler[i] = handler;
return 0;
}
interrupt U0 @pci_interrupt_handler() {
I64 i;
for (i = 0; i < PCI_INTH_MAX; i++)
if (@pci_int_handler[i])
Call(@pci_int_handler[i]);
*(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0;
}
MemSet(&@pci_int_handler, NULL, sizeof(U64) * PCI_INTH_MAX);
// IntEntrySet(0x40, &@pci_interrupt_handler, IDTET_IRQ);
// IntEntrySet(0x41, &@pci_interrupt_handler, IDTET_IRQ);
// IntEntrySet(0x42, &@pci_interrupt_handler, IDTET_IRQ);
// IntEntrySet(0x43, &@pci_interrupt_handler, IDTET_IRQ);
//@pci_reroute_interrupts(0x40, 0);

View file

@ -0,0 +1,76 @@
// vim: set ft=c:
I64 start_buf_num;
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
U0 AudioFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
{
I64 j=0,k;
I64 intL, intR;
U8 *buf2;
if (paused)
{
while (j<SND_BUF_LEN)
{
buf[j++]=0;
buf[j++]=0;
}
return;
}
while (j<SND_BUF_LEN)
{
// TODO: fix this - dirty hack to keep audio in sync
if (FifoI64Cnt(audio_fifo_L)>8192)
{
while (FifoI64Cnt(audio_fifo_L)>7680)
{
FifoI64Rem(audio_fifo_L, &k);
FifoI64Rem(audio_fifo_R, &k);
}
}
if (FifoI64Cnt(audio_fifo_L))
{
FifoI64Rem(audio_fifo_L, &intL);
}
else
{
intL = 0;
}
intL *= 0xFFFF;
if (intL < 0)
{
intL += 0x1000000;
}
if (FifoI64Cnt(audio_fifo_R))
{
FifoI64Rem(audio_fifo_R, &intR);
}
else
{
intR = 0;
}
intR *= 0xFFFF;
if (intR < 0)
{
intR += 0x1000000;
}
buf2 = buf+j;
buf2[0] = 0;
buf2[1] = intL;
buf2[2] = intL >> 8;
buf2[3] = intL >> 16;
j++;
buf2 = buf+j;
buf2[0] = 0;
buf2[1] = intR;
buf2[2] = intR >> 8;
buf2[3] = intR >> 16;
j++;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
Cd(__DIR__);
SysFile("Sup1CodeScraps/Mem/Mem2Meg.ZC");
SysFile("Sup1Snd/MakeSnd.ZC");
SysFile("Sup1HDAudio/HDAudio.ZC");


View file

@ -0,0 +1,199 @@
//Now, we use 1 Gig page table entries.
//See $LK,"./UncachedAlloc.ZC"$
U8 *Mem2MegAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL)
{/*Alloc 2Meg pages from BlkPool. Don't link to task.
(Linking to a task means they will be freed when the task dies.)
It might give you more than you asked for
so a ptr to a page count is passed.
Return: NULL if out of memory.
*/
I64 i,j,*pte,num=*_pages2Meg;
CMemBlk *res=NULL,*m,*m1;
if (!bp) bp=sys_code_bp;
PUSHFD
CLI
while (LBts(&bp->locked_flags,BPlf_LOCKED))
PAUSE
num<<=21-MEM_PAG_BITS;
m=&bp->mem_free_2meg_list;
while (TRUE) {
if (!(res=m->next))
break;
if (res->pags<num)
m=res;
else {
if (res->pags==num) {
m->next=res->next;
goto am_done;
} else {
res->pags-=num;
res(U8 *)+=res->pags<<MEM_PAG_BITS;
res->pags=num;
goto am_done;
}
}
}
m=&bp->mem_free_list;
while (TRUE) {
if (!(res=m->next)) {
num=0;
res=NULL; //Out of memory
goto am_done;
}
if (res->pags<num)
m=res;
else {
if (res->pags==num) {
if (res(U8 *)&0x1FFFFF)
m=res;
else {
m->next=res->next;
goto am_done;
}
} else {
if (i=(res(U8 *)&0x1FFFFF)>>MEM_PAG_BITS) {
j=1<<(21-MEM_PAG_BITS)-i;
if (res->pags<num+j)
m=res;
else if (res->pags==num+j) {
res->pags-=num;
res(U8 *)+=res->pags<<MEM_PAG_BITS;
res->pags=num;
goto am_done;
} else {
m1=res;
res(U8 *)+=j<<MEM_PAG_BITS;
res->pags=num;
m=res(U8 *)+num<<MEM_PAG_BITS;
m->pags=m1->pags-num-j;
m1->pags=j;
m->next=m1->next;
m1->next=m;
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
goto am_done;
}
} else {
m=m->next=res(U8 *)+num<<MEM_PAG_BITS;
m->next=res->next;
m->pags=res->pags-num;
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
res->pags=num;
goto am_done;
}
}
}
}
am_done:
i=num<<MEM_PAG_BITS;
bp->used_u8s+=i;
num>>=21-MEM_PAG_BITS;
*_pages2Meg=num;
m=res;
m1=m(U8 *)+i;
while (m<m1) {
pte=MemPageTable(m);
*pte &= ~0x18;
InvalidatePage(m);
m(U8 *)+=0x200000;
}
LBtr(&bp->locked_flags,BPlf_LOCKED);
POPFD
return res;
}
U8 *Mem2MegUncachedAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL)
{/*Alloc 2Meg pages from BlkPool. Don't link to task.
(Linking to a task means they will be freed when the task dies.)
It will be marked uncached. It might give you more than you asked for
so a ptr to a page count is passed.
Return: NULL if out of memory.
*/
CMemBlk *res,*m,*m1;
I64 num=*_pages2Meg,*pte;
if (res=Mem2MegAlloc(_pages2Meg,bp)) {
num=*_pages2Meg;
m=res;
m1=m(U8 *)+num<<21;
while (m<m1) {
pte=MemPageTable(m);
*pte= *pte& ~0x18 |0x10;
InvalidatePage(m);
m(U8 *)+=0x200000;
}
}
return res;
}
U8 *Mem2MegWriteThruAlloc(I64 *_pages2Meg,CBlkPool *bp=NULL)
{/*Alloc 2Meg pages from BlkPool. Don't link to task.
(Linking to a task means they will be freed when the task dies.)
It will be marked write-through. It might give you more than you asked for
so a ptr to a page count is passed.
Return: NULL if out of memory.
*/
CMemBlk *res,*m,*m1;
I64 num=*_pages2Meg,*pte;
if (res=Mem2MegAlloc(_pages2Meg,bp)) {
num=*_pages2Meg;
m=res;
m1=m(U8 *)+num<<21;
while (m<m1) {
pte=MemPageTable(m);
*pte= *pte& ~0x18 |8;
InvalidatePage(m);
m(U8 *)+=0x200000;
}
}
return res;
}
U0 Mem2MegFree(CMemBlk *m,I64 pages2Meg,CBlkPool *bp=NULL)
{//Return non-task 2Meg pages to BlkPool.
I64 *pte;
CMemBlk *m1,*m2;
if (m) {
if (!bp) bp=sys_code_bp;
m2=m;
m1=m(U8 *)+pages2Meg<<21;
while (m2<m1) {
pte=MemPageTable(m2);
*pte=*pte & ~0x18;
InvalidatePage(m2);
m2(U8 *)+=0x200000;
}
PUSHFD
CLI
while (LBts(&bp->locked_flags,BPlf_LOCKED))
PAUSE
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
m->pags=pages2Meg<<(21-MEM_PAG_BITS);
bp->used_u8s-=pages2Meg<<21;
m->next=bp->mem_free_2meg_list;
bp->mem_free_2meg_list=m;
LBtr(&bp->locked_flags,BPlf_LOCKED);
POPFD
}
}
CHeapCtrl *HeapCtrlBPInit(CBlkPool *bp,I64 pags)
{//Make mem chunk into HeapCtrl and BlkPool.
I64 num;
CMemBlk *m;
CHeapCtrl *hc;
MemSet(bp,0,sizeof(CBlkPool)+sizeof(CHeapCtrl));
hc=HeapCtrlInit(bp(U8 *)+sizeof(CBlkPool),,bp);
m=(bp(U8 *)+sizeof(CBlkPool)+sizeof(CHeapCtrl)+MEM_PAG_SIZE-1)&
~(MEM_PAG_SIZE-1);
num=(bp(U8 *)+pags<<MEM_PAG_BITS-m(U8 *))>>MEM_PAG_BITS;
bp->alloced_u8s=(pags-num)<<MEM_PAG_BITS;
BlkPoolAdd(bp,m,num);
return hc;
}

View file

@ -0,0 +1,68 @@
Bool beat_done;
I64 start_buf_num;
U0 (*fp_task_end_cb)();
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
F64 freq1,freq2;
U0 BeatFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
{ //Gets called by HD Audio task -- HDAudioTask().
I64 j,m;
F64 t;
if (beat_done) return;
t=ToF64((buf_num-start_buf_num)*(SND_BUF_LEN/SND_OCHANNELS))/SND_SAMPLE_RATE;
j=0;
while (j<SND_BUF_LEN) {
m=I32_MAX*(Sin(freq1*(2*ã)*t)+Sin(freq2*(2*ã)*t));
//Samples are 24-bit, placed in upper 24 bits of an I32.
m*=snd_vol;
buf[j++]=ToI64(m)&0xFFFFFF00; //Left
buf[j++]=ToI64(m)&0xFFFFFF00; //Right
t+=1.0/SND_SAMPLE_RATE;
}
}
U0 BeatTaskEndCB()
{
beat_done=TRUE;
fp_snd_fill_buf=fp_old_fill_buf;
if (fp_task_end_cb)
(*fp_task_end_cb)();
else
Exit;
}
U0 BeatFreq()
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
freq1=600.0;
freq2=601.0;
beat_done=FALSE;
fp_task_end_cb=Fs->task_end_cb;
Fs->task_end_cb=&BeatTaskEndCB; //Catch <CTRL-ALT-X> or Kill() task
start_buf_num=snd_obuf_num;
fp_old_fill_buf=fp_snd_fill_buf;
fp_snd_fill_buf=&BeatFillBuf;
try {
"Pick two frequencies within a few Hz of each other to hear beats.\n"
"Pick two frequencies a multiple of two for an octave harmonic.\n"
"$$FG,GREEN$$<CTRL-ALT-C>$$FG$$ to exit.\n";
while (TRUE) {
freq1=PmtF64("Freq #1 (%0.2fHz):",freq1,20,20000);
freq2=PmtF64("Freq #2 (%0.2fHz):",freq2,20,20000);
}
} catch { //Catch <CTRL-ALT-C>, but pass it on to next higher handler.
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
}
beat_done=TRUE;
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
}
BeatFreq;

View file

@ -0,0 +1,16 @@
U0 Chords(Bool val=ON)
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
HDTonesInit;
if (val) {
hda.tone_swcs[1]->freq_multiplier=4.0/3.0;
hda.tone_swcs[1]->amp_multiplier=1.0;
hda.tone_swcs[2]->freq_multiplier=(4.0/3.0)`2;
hda.tone_swcs[2]->amp_multiplier=1.0;
}
}
Chords(ON);

View file

@ -0,0 +1,99 @@
Bool echo_done;
U0 (*fp_task_end_cb)();
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
U0 (*fp_old_copy_buf)(SND_IN_CONTAINER *buf,I64 buf_num)=NULL;
#define BUF_NUM 8
SND_IN_CONTAINER my_buf[SND_BUF_LEN*BUF_NUM];
I64 my_ibuf_ptr,my_obuf_ptr;
U0 EchoFillBuf(SND_OUT_CONTAINER *buf,I64)
{
I64 j;
if (echo_done) return;
j=0;
while (j<SND_BUF_LEN) {
buf[j++]=ToI64(snd_vol*my_buf[my_obuf_ptr++
&(SND_BUF_LEN*BUF_NUM-1)])<<16&0xFFFFFF00;
buf[j++]=ToI64(snd_vol*my_buf[my_obuf_ptr++
&(SND_BUF_LEN*BUF_NUM-1)])<<16&0xFFFFFF00;
}
}
U0 EchoCopyBuf(SND_IN_CONTAINER *buf,I64)
{
I64 j;
if (echo_done) return;
j=0;
while (j<SND_BUF_LEN) {
my_buf[my_ibuf_ptr++ &(SND_BUF_LEN*BUF_NUM-1)]=buf[j++];
my_buf[my_ibuf_ptr++ &(SND_BUF_LEN*BUF_NUM-1)]=buf[j++];
}
}
U0 EchoTaskEndCB()
{
echo_done=TRUE;
HDStop(TRUE,FALSE);
fp_snd_fill_buf=fp_old_fill_buf;
fp_snd_copy_buf=fp_old_copy_buf;
if (fp_task_end_cb)
(*fp_task_end_cb)();
else
Exit;
}
U0 DrawIt(CTask *task,CDC *dc)
{
SND_IN_CONTAINER *buf=hda.istr0_buf[0];
I64 i,x1,y1,x2=0,y2=0,
cy=task->pix_height>>1;
dc->color=BLUE;
for (i=0;i<SND_BUF_LEN;i++) {
x1=i*task->pix_width/SND_BUF_LEN;
y1=cy-buf[i]*cy/I16_MAX;
GrLine(dc,x2,y2,x1,y1);
x2=x1;
y2=y1;
}
}
U0 EchoDemo()
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
HDRun(TRUE,TRUE);
echo_done=FALSE;
fp_task_end_cb=Fs->task_end_cb;
Fs->task_end_cb=&EchoTaskEndCB; //Catch <CTRL-ALT-X> or Kill() task
my_ibuf_ptr=(BUF_NUM/2)*SND_BUF_LEN;
my_obuf_ptr=0;
fp_old_fill_buf=fp_snd_fill_buf;
fp_old_copy_buf=fp_snd_copy_buf;
fp_snd_fill_buf=&EchoFillBuf;
fp_snd_copy_buf=&EchoCopyBuf;
DocCursor;
DocClear;
Fs->draw_it=&DrawIt;
try
CharGet;
catch { //Catch <CTRL-ALT-C>, but pass it on to next higher handler.
fp_snd_fill_buf=fp_old_fill_buf;
fp_snd_copy_buf=fp_old_copy_buf;
Fs->task_end_cb=fp_task_end_cb;
}
echo_done=TRUE;
HDStop(TRUE,FALSE);
fp_snd_fill_buf=fp_old_fill_buf;
fp_snd_copy_buf=fp_old_copy_buf;
Fs->task_end_cb=fp_task_end_cb;
SettingsPop;
}
EchoDemo;


View file

@ -0,0 +1,17 @@
U0 Guitar(Bool val=ON,F64 à=0.7)
{
I64 i;
F64 m;
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
HDTonesInit;
if (val)
for (i=0,m=1.0;i<HD_TONES;i++,m*=à) {
hda.tone_swcs[i]->freq_multiplier=i+1;
hda.tone_swcs[i]->amp_multiplier=m;
}
}
Guitar(ON);

View file

@ -0,0 +1,96 @@
Bool poly_done;
I64 start_buf_num;
U0 (*fp_task_end_cb)();
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
U0 PolyFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
{ //Gets called by HD Audio task -- HDAudioTask().
//Note: the buffer is in uncached memory
//so you might want to avoid multiple
//accesses due to slow speed. (If you were
//to add a bunch of waveforms together, you
//might want to do it in a cached buffer
//and copy it once.)
I64 j,m,r;
F64 t,d;
if (poly_done) return;
t=ToF64((buf_num-start_buf_num)*(SND_BUF_LEN/SND_OCHANNELS))/SND_SAMPLE_RATE;
j=0;
while (j<SND_BUF_LEN) {
d=0.5*Sin(1.0*(2*ã)*t)+0.5; //Stereo pos from 0.0-1.0
r=RandI32;
m=0;
m+=0.2*I32_MAX*Caw(t,0.25)*Sin(220.0*(2*ã)*t);
m+=0.2*I32_MAX*Caw(t,0.25)*Sin(222.0*(2*ã)*t);
m+=0.2*I32_MAX*Caw(t,0.25)*Sin(880.0*(2*ã)*t);
m+=0.2*I32_MAX*Caw(t,0.25)*Sin(884.0*(2*ã)*t);
m+=0.4*r*Caw(t,.125);
if (Caw(t-.25,0.5)<=0.05)
m+=0.3*r*Caw(t,0.05);
if (t>4.0) {
if (0.90<Caw(t,1.0))
m+=0.6*I32_MAX*Caw(t,0.1)*FullCaw(t,0.001);
if (t>8.0) {
if (0.70<Caw(t,1.0)<0.90)
m+=0.4*I32_MAX*Caw(t-.7,0.5)*FullCaw(t,0.00075);
if (t>12.0) {
if (0.30<Caw(t,1.0)<0.40)
m+=0.4*I32_MAX*Sin(100.0/(1.1-Saw(t,0.01)));
if (t>16.0)
m+=0.3*I32_MAX*Caw(t,1.0/6)*Sin(440.0*(2*ã)*t);
}
}
}
//Samples are 24-bit, placed in upper 24 bits of an I32.
m*=snd_vol;
buf[j++]=ToI64(m*d)&0xFFFFFF00; //Left
buf[j++]=ToI64(m*(1.0-d))&0xFFFFFF00; //Right
t+=1.0/SND_SAMPLE_RATE;
}
}
U0 PolyTaskEndCB()
{
poly_done=TRUE;
fp_snd_fill_buf=fp_old_fill_buf;
if (fp_task_end_cb)
(*fp_task_end_cb)();
else
Exit;
}
U0 PolyPhonic()
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
poly_done=FALSE;
fp_task_end_cb=Fs->task_end_cb;
Fs->task_end_cb=&PolyTaskEndCB; //Catch <CTRL-ALT-X> or Kill() task
start_buf_num=snd_obuf_num;
fp_old_fill_buf=fp_snd_fill_buf;
fp_snd_fill_buf=&PolyFillBuf;
try
#if __CMD_LINE__
PressAKey;
#else
View;
#endif
catch { //Catch <CTRL-ALT-C>, but pass it on to next higher handler.
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
}
poly_done=TRUE;
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
}
#if __CMD_LINE__
PolyPhonic;
#endif

View file

@ -0,0 +1,117 @@
Bool record_stop,record_done;
U0 (*fp_old_copy_buf)(SND_IN_CONTAINER *buf,I64 buf_num)=NULL;
#define RECORD_BUF_SIZE (SND_BUF_LEN*0x100)
SND_IN_CONTAINER *record_buf[2];
I64 record_buf_iptr,record_ibuf_num,record_obuf_num;
U0 RecordCopyBuf(SND_IN_CONTAINER *buf,I64)
{
I64 j;
SND_IN_CONTAINER *_s=record_buf[record_ibuf_num&1];
j=0;
while (j<SND_BUF_LEN) {
_s[record_buf_iptr++]=buf[j++];
j++; //Record in mono
}
if (record_buf_iptr>=RECORD_BUF_SIZE) {
record_buf_iptr=0;
record_ibuf_num++;
}
}
U0 DrawIt(CTask *task,CDC *dc)
{
SND_IN_CONTAINER *buf=hda.istr0_buf[0];
I64 i,x1,y1,x2=0,y2=0,
cy=task->pix_height>>1;
dc->color=BLUE;
for (i=0;i<SND_BUF_LEN;i++) {
x1=i*task->pix_width/SND_BUF_LEN;
y1=cy-buf[i]*cy/I16_MAX;
GrLine(dc,x2,y2,x1,y1);
x2=x1;
y2=y1;
}
dc->color=RED;
}
U0 RecordTaskEndCB()
{
fp_snd_copy_buf=fp_old_copy_buf;
HDStop(TRUE,FALSE);
Free(record_buf[0]);
Free(record_buf[1]);
record_done=TRUE;
Exit;
}
U0 RecordTask(U8 *filename)
{
Bool old_io_snd;
U8 *filename=StrNew(filename),*filename2;
TaskInitExt; //needed for disk access
record_buf[0]=CAlloc(RECORD_BUF_SIZE*sizeof(SND_IN_CONTAINER));
record_buf[1]=CAlloc(RECORD_BUF_SIZE*sizeof(SND_IN_CONTAINER));
FileExtRemove(filename);
record_buf_iptr=0;
record_ibuf_num=0;
record_obuf_num=0;
record_done=FALSE;
Fs->task_end_cb=&RecordTaskEndCB;
fp_old_copy_buf=fp_snd_copy_buf;
fp_snd_copy_buf=&RecordCopyBuf;
HDRun(TRUE,FALSE);
old_io_snd=IOSnd(OFF);
while (!record_stop) {
if (record_ibuf_num>record_obuf_num) {
filename2=MPrint("%s%04d.SNZ",filename,record_obuf_num);
SndFileWrite(filename2,record_buf[record_obuf_num&1],RECORD_BUF_SIZE);
record_obuf_num++;
Free(filename2);
}
Sleep(1);
}
filename2=MPrint("%s%04d.SNZ",filename,record_obuf_num);
SndFileWrite(filename2,record_buf[record_obuf_num&1],record_buf_iptr);
record_obuf_num++;
Free(filename2);
Free(filename);
IOSnd(old_io_snd);
record_done=TRUE;
}
U0 RecordDemo(U8 *filename="~/Record.SNZ")
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
record_done=FALSE;
record_stop=FALSE;
Spawn(&RecordTask,filename,"Record .SNZ",,Fs);
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
DocCursor;
DocClear;
Fs->draw_it=&DrawIt;
try
CharGet;
catch //Catch <CTRL-ALT-C>, but pass it on to next higher handler.
record_stop=TRUE;
record_stop=TRUE;
while (record_done)
Yield;
SettingsPop;
while (TRUE) {
"\n\nPlay ";
if (YorN)
SndFilePlaySeq(filename,record_obuf_num);
else
break;
}
NewLine(2);
}
RecordDemo;

View file

@ -0,0 +1,44 @@
U0 DrawIt(CTask *task,CDC *dc)
{
SND_OUT_CONTAINER *buf=hda.ostr0_buf[0];
I64 i,x1,y1,x2,y2,
cy=task->pix_height>>1;
dc->color=BLUE;
x2=0;y2=cy;
for (i=0;i<SND_BUF_LEN;i+=2) {
x1=i*task->pix_width/SND_BUF_LEN;
y1=cy-buf[i]*cy/snd_vol/I32_MAX;
GrLine(dc,x2,y2,x1,y1);
x2=x1;y2=y1;
}
dc->color=GREEN;
x2=0;y2=cy;
for (i=1;i<SND_BUF_LEN;i+=2) {
x1=i*task->pix_width/SND_BUF_LEN;
y1=cy-buf[i]*cy/snd_vol/I32_MAX;
GrLine(dc,x2,y2,x1,y1);
x2=x1; y2=y1;
}
}
U0 SndScope()
{
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
WinHorz(1,18);
WinVert(15,TEXT_ROWS-2);
DocCursor;
DocClear;
Fs->draw_it=&DrawIt;
CharGet;
SettingsPop;
}
#if __CMD_LINE__
SndScope;
#endif

View file

@ -0,0 +1,280 @@
#define M_WAVEFORM 0
#define M_FREQUENCY 1
#define M_ENVELOPE 2
#define M_MODES_NUM 3
I64 mode;
Bool my_ms_down;
I64 last_x,last_y;
Bool synth_done;
U0 (*fp_task_end_cb)();
U0 (*fp_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL;
#define BUF_NUM 8
SND_OUT_CONTAINER my_buf[SND_BUF_LEN*BUF_NUM];
#define WF_BUF_LEN 2048
#define WF_Y_SCALE 2048.0
I64 waveform_buf[WF_BUF_LEN];
#define FQ_BUF_LEN 2048
#define FQ_Y_SCALE 2048.0
I64 frequency_buf[FQ_BUF_LEN];
F64 fq_scale;
#define EL_BUF_LEN 2048
#define EL_Y_SCALE 2048.0
I64 envelope_buf[EL_BUF_LEN];
F64 el_scale;
U0 SynthFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num)
{
I64 i,j,l,k0,k1,k2,k3;
F64 d;
static F64 k=0;
if (synth_done) return;
j=0;
k0=buf_num*(SND_BUF_LEN/SND_OCHANNELS);
while (j<SND_BUF_LEN) {
k1=WF_BUF_LEN*k/(SND_BUF_LEN/SND_OCHANNELS);
k2=fq_scale*FQ_BUF_LEN*k0/(SND_BUF_LEN/SND_OCHANNELS);
k3=el_scale*EL_BUF_LEN*k0/(SND_BUF_LEN/SND_OCHANNELS);
d=envelope_buf[k3%EL_BUF_LEN]/EL_Y_SCALE;
d*=snd_vol;
d*=I32_MAX*waveform_buf[k1%WF_BUF_LEN]/WF_Y_SCALE;
i=ToI64(d)&0xFFFFFF00;
for (l=0;l<SND_OCHANNELS;l++)
buf[j++]=i;
d=frequency_buf[k2%FQ_BUF_LEN]/FQ_Y_SCALE; // [0.0,1.0]
d=(SND_BUF_LEN/SND_OCHANNELS)*Exp(5.0*d+4)/SND_SAMPLE_RATE;
k+=d;
k0++;
}
}
U0 SynthTaskEndCB()
{
synth_done=TRUE;
HDStop(TRUE,FALSE);
fp_snd_fill_buf=fp_old_fill_buf;
if (fp_task_end_cb)
(*fp_task_end_cb)();
else
Exit;
}
Bool WFPlot(U8 *,I64 x,I64 y,I64)
{
if (0<=x<=WF_BUF_LEN)
waveform_buf[x]=y;
return TRUE;
}
Bool FQPlot(U8 *,I64 x,I64 y,I64)
{
if (0<=x<=FQ_BUF_LEN)
frequency_buf[x]=AbsI64(y);
return TRUE;
}
Bool ELPlot(U8 *,I64 x,I64 y,I64)
{
if (0<=x<=EL_BUF_LEN)
envelope_buf[x]=AbsI64(y);
return TRUE;
}
U0 DrawIt(CTask *task,CDC *dc)
{
I64 i,x1,y1,x2,y2,
cy=task->pix_height>>1,
h_max=task->pix_width-1;
if (!winmgr.show_menu) {
if (mouse.lb) {
if (my_ms_down)
switch (mode) {
case M_WAVEFORM:
Line(NULL,
(last_x-task->pix_left-task->scroll_x)*WF_BUF_LEN/h_max,
WF_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0,
( msx-task->pix_left-task->scroll_x)*WF_BUF_LEN/h_max,
WF_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0,
&WFPlot);
break;
case M_FREQUENCY:
Line(NULL,
(last_x-task->pix_left-task->scroll_x)*FQ_BUF_LEN/h_max,
FQ_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0,
( msx-task->pix_left-task->scroll_x)*FQ_BUF_LEN/h_max,
FQ_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0,
&FQPlot);
break;
case M_ENVELOPE:
Line(NULL,
(last_x-task->pix_left-task->scroll_x)*EL_BUF_LEN/h_max,
EL_Y_SCALE*(cy-last_y+task->pix_top+task->scroll_y)/cy,0,
( msx-task->pix_left-task->scroll_x)*EL_BUF_LEN/h_max,
EL_Y_SCALE*(cy-msy+task->pix_top+task->scroll_y)/cy,0,
&ELPlot);
break;
}
my_ms_down=TRUE;
last_x=msx;
last_y=msy;
} else
my_ms_down=FALSE;
}
x2=-1;
if (mode==M_WAVEFORM && Blink) {
dc->color=ROPF_DITHER+WHITE<<16+RED;
GrPrint(dc,0,cy-FONT_HEIGHT,"Set Waveform.");
} else
dc->color=RED;
for (i=0;i<WF_BUF_LEN;i++) {
x1=i*task->pix_width/WF_BUF_LEN;
y1=cy-cy*waveform_buf[i]/WF_Y_SCALE;
if (x2>=0)
GrLine(dc,x2,y2,x1,y1);
x2=x1;
y2=y1;
}
x2=-1;
if (mode==M_FREQUENCY && Blink) {
dc->color=ROPF_DITHER+WHITE<<16+BLUE;
GrPrint(dc,0,cy-FONT_HEIGHT,"Set Frequency.");
} else
dc->color=BLUE;
for (i=0;i<FQ_BUF_LEN;i++) {
x1=i*task->pix_width/FQ_BUF_LEN;
y1=cy-cy*frequency_buf[i]/FQ_Y_SCALE;
if (x2>=0)
GrLine(dc,x2,y2,x1,y1);
GrLine(dc,x2,cy-(y2-cy),x1,cy-(y1-cy));
x2=x1;
y2=y1;
}
x2=-1;
if (mode==M_ENVELOPE && Blink) {
dc->color=ROPF_DITHER+WHITE<<16+GREEN;
GrPrint(dc,0,cy-FONT_HEIGHT,"Set Envelope.");
} else
dc->color=GREEN;
for (i=0;i<EL_BUF_LEN;i++) {
x1=i*task->pix_width/EL_BUF_LEN;
y1=cy-cy*envelope_buf[i]/EL_Y_SCALE;
if (x2>=0)
GrLine(dc,x2,y2,x1,y1);
GrLine(dc,x2,cy-(y2-cy),x1,cy-(y1-cy));
x2=x1;
y2=y1;
}
dc->color=BLACK;
GrLine(dc,0,cy,task->pix_width,cy);
}
U0 SetMenu()
{
MenuEntryFind(Fs->cur_menu,"Mode/Waveform")->checked=mode==M_WAVEFORM;
MenuEntryFind(Fs->cur_menu,"Mode/Frequency")->checked=mode==M_FREQUENCY;
MenuEntryFind(Fs->cur_menu,"Mode/Envelope")->checked=mode==M_ENVELOPE;
}
U0 Init()
{
my_ms_down=FALSE;
mode=M_WAVEFORM;
MemSetI64(&waveform_buf[0] ,-0.5 *WF_Y_SCALE,WF_BUF_LEN/2);
MemSetI64(&waveform_buf[WF_BUF_LEN/2] , 0.5 *WF_Y_SCALE,WF_BUF_LEN/2);
MemSetI64(frequency_buf , 0.25*FQ_Y_SCALE,FQ_BUF_LEN);
MemSetI64(envelope_buf , 0.75*EL_Y_SCALE,EL_BUF_LEN);
fq_scale=0.02;
el_scale=0.02;
SetMenu;
}
U0 Synth()
{
I64 arg1,arg2;
if (snd_dev!=SD_HD_AUDIO) {
"Only works for HD Audio.\n";
return;
}
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
MenuPush(
"File {"
" New(,'\n');"
" Abort(,CH_SHIFT_ESC);"
" Exit(,CH_ESC);"
"}"
"Mode {"
" Waveform(,'1');"
" Frequency(,'2');"
" Envelope(,'3');"
"}"
);
AutoComplete;
WinBorder;
WinMax;
DocCursor;
DocClear;
Fs->win_inhibit=WIG_TASK_DEFAULT-WIF_SELF_FOCUS-WIF_FOCUS_TASK_MENU;
Init;
synth_done=FALSE;
fp_task_end_cb=Fs->task_end_cb;
Fs->task_end_cb=&SynthTaskEndCB; //Catch <CTRL-ALT-X> or Kill() task
fp_old_fill_buf=fp_snd_fill_buf;
fp_snd_fill_buf=&SynthFillBuf;
Fs->draw_it=&DrawIt;
try {
while (TRUE) {
switch (MessageGet(&arg1,&arg2,1<<MESSAGE_KEY_DOWN+1<<MESSAGE_MS_R_DOWN)) {
case MESSAGE_KEY_DOWN:
switch (arg1) {
case '1':
case '2':
case '3':
mode=arg1-'1';
SetMenu;
break;
case '\n':
Init;
break;
case CH_SHIFT_ESC:
case CH_ESC:
goto sy_done;
}
break;
case MESSAGE_MS_R_DOWN:
if (++mode==M_MODES_NUM)
mode=0;
break;
}
}
sy_done:
MessageGet(,,1<<MESSAGE_KEY_UP);
} catch { //Catch <CTRL-ALT-C>, but pass it on to next higher handler.
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
}
synth_done=TRUE;
fp_snd_fill_buf=fp_old_fill_buf;
Fs->task_end_cb=fp_task_end_cb;
SettingsPop;
}
Synth;


View file

@ -0,0 +1,697 @@
//SysFile("~/sup1hdaudio/Sup1CodeScraps/Mem/Mem2Meg.ZC");
#
help_index "Sound/HDAudio"
//snd devs
#define SD_PC_SPEAKER 0
#define SD_HD_AUDIO 1
#define SND_SAMPLE_RATE 48000
#define SND_SAMPLE_BITS 24
#define SND_OCHANNELS 2
#define SND_ICHANNELS 2
#define SND_OUT_CONTAINER I32
#define SND_IN_CONTAINER I16
#define SND_BUF_LEN 0x400
#define SND_BUF_TIME_mS(SND_BUF_LEN / SND_OCHANNELS *1000.0 / \
SND_SAMPLE_RATE)
F64 snd_freq = 0;
I64 snd_dev = SD_PC_SPEAKER;
Bool snd_record = FALSE;
F64 snd_vol = 0.1;
U0(*fp_snd)(F64 freq, I64 waveform, F64 amp) = NULL;
U0(*fp_snd_record)(F64 freq, I64 waveform, F64 amp) = NULL;
U0(*fp_snd_fill_buf)(SND_OUT_CONTAINER *buf, I64 buf_num) = NULL;
U0(*fp_snd_copy_buf)(SND_IN_CONTAINER *buf, I64 buf_num) = NULL;
I64 snd_obuf_num, snd_ibuf_num;
#define Sf_FILLING_OUT 0
I64 snd_flags;
#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_SEL_GET 0xF0100
#define VERB_CONNECT_SEL_SET 0x70100
#define VERB_GET_CONNECT_LST 0xF0200
#define VERB_PROCESS_STATE_GET 0xF0300
#define VERB_PROCESS_STATE_SET 0x70300
#define VERB_COEFF_IDX_GET 0xD0000
#define VERB_COEFF_IDX_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_SEL_GET 0xF0400
#define VERB_SDI_SEL_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
DefineListLoad("ST_AUDIO_WIDGET_TYPES",
"Output\0Input\0Mixer\0Sellector\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;
CBlkPool * bp;
CHeapCtrl * hc;
I64 cad;
U32 * corb;
I64 * rirb;
CHDBufDesc *ostr0_bdl, *istr0_bdl;
SND_OUT_CONTAINER *ostr0_buf[2], *o_tmp_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;
MemSet(&hda, 0, sizeof(CHDAudioCtrl));
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, res = 0;
_w = hda.bar + HD_RIRBWP;
wp = *_w;
while (hda.rirb_rp != wp)
res = hda.rirb[++hda.rirb_rp];
return res;
}
I64 HDReadRIRB()
{
U16 * _w;
I64 wp, res = 0;
_w = hda.bar + HD_RIRBWP;
do {
Yield;
wp = *_w;
} while (wp == hda.rirb_rp);
res = hda.rirb[++hda.rirb_rp];
return res;
}
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;
I64 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_SEL_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++)
//Set IN amps to mute
HDWriteCORBSync(cad, nid, VERB_AMPLIFIER_GAIN_SET + 0x7080 + i << 8);
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_tmp_buf)
hda.o_tmp_buf = SysMAlloc(size);
MemSet(hda.o_tmp_buf, 0, size);
for (i = 0; i < HD_TONES; i++)
SndWaveAddBuf(hda.tone_swcs[i], hda.o_tmp_buf,
SND_BUF_LEN / SND_OCHANNELS, hda.freq,
hda.waveform, snd_vol *hda.amp);
MemCopy(buf, hda.o_tmp_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.bar)
{
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;
Sound;
fp_snd = &HDSnd;
fp_snd_fill_buf = &HDFillBuf;
fp_snd_copy_buf = NULL;
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));
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.bar)
{
Kill(hda.task);
hda.task = NULL;
if (rst)
HDRst;
Free(hda.corb);
Free(hda.rirb);
Free(hda.o_tmp_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);
hda.bar = NULL;
}
}
U0 HDAudioUncachedInit()
{
I64 shared_blks = 1;
hda.bp = Mem2MegUncachedAlloc(&shared_blks);
hda.hc = HeapCtrlBPInit(hda.bp, shared_blks << 12);
}
public Bool HDAudioInit(I64 hd_bus, I64 hd_dev, I64 hd_fun)
{
I64 i;
U32 * _d;
U16 w, *_w;
U8 * _b;
if (hda.bar)
HDAudioEnd;
else
HDAudioUncachedInit;
if (PCIReadU16(hd_bus, hd_dev, hd_fun, 0) == 0x8086 &&
(hda.bar = PCIReadU32(hd_bus, hd_dev, hd_fun, 0x10) &~(0x1F)))
{
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, hda.hc);
_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, hda.hc);
_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, hda.hc);
_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, hda.hc);
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, hda.hc);
_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, hda.hc);
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 idx
_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 idx
_w = hda.bar + ISTR0 + STRFMT;
*_w = HD_DFT_IN_FMT;
LBts(&sys_semas[SEMA_SOUND], 0); //turn off until cfg completed
LBtr(&snd_flags, Sf_FILLING_OUT);
hda.audio_task_started = FALSE;
if (mp_count > 1)
hda.task = Spawn(&HDAudioTask, NULL, "HD Audio", 3);
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
hda.bar = NULL;
return FALSE;
}
Bool HDAudioScan()
{
I64 i = -1, j;
while (TRUE)
{
j = PCIClassFind(0x040300, ++i);
if (j < 0)
return FALSE;
if (HDAudioInit(j.u8[2], j.u8[1], j.u8[0]))
return TRUE;
}
}
HDAudioScan;
#
help_index ""

View file

@ -0,0 +1,720 @@
#define CONNECTS_NUM 16
class MyMass: CMass
{
F64 radius;
U8 nid, type, num_connects, cur_connect;
U32 audio_widget_capabilities;
U8 connect_lst[CONNECTS_NUM];
U8 gain_lst[CONNECTS_NUM];
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;
I16 * buf;
I64 i, cxx, cyy,
cy = task->pix_height >> 1;
F64 dx, dy, d;
MyMass * tmpm;
MySpring * tmps;
old_suspend = Suspend(task);
tmps = ode->next_spring;
while (tmps != &ode->next_spring)
{
dc->color = tmps->color;
GrLine(dc, tmps->end1->x, tmps->end1->y,
tmps->end2->x, tmps->end2->y);
cxx = (tmps->end1->x + tmps->end2->x) / 2;
cyy = (tmps->end1->y + tmps->end2->y) / 2;
dx = tmps->end1->x - tmps->end2->x;
dy = tmps->end1->y - tmps->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);
tmps = tmps->next;
}
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
if (tmpm->disabled)
dc->color = BLUE;
else
dc->color = LTBLUE;
GrCircle(dc, tmpm->x, tmpm->y, tmpm->radius);
GrPrint(dc, tmpm->x, tmpm->y - FONT_HEIGHT / 2, "%02X%3tZ",
tmpm->nid, tmpm->type,
"ST_AUDIO_WIDGET_TYPES");
tmpm = tmpm->next;
}
Suspend(task, old_suspend);
dc->color = BLUE;
buf = hda.istr0_buf[0];
for (i = 0; i < SND_BUF_LEN; i++)
GrPlot(dc, i *task->pix_width / SND_BUF_LEN,
cy - buf[i] *cy / I16_MAX);
}
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->pix_width, v = task->pix_height;
F64 d, dd;
CD3 p;
MyMass *tmpm1, *tmpm2;
tmpm1 = ode->next_mass;
while (tmpm1 != &ode->next_mass)
{
tmpm2 = tmpm1->next;
while (tmpm2 != &ode->next_mass)
{
D3Sub(&p, &tmpm2->state->x, &tmpm1->state->x);
dd = D3NormSqr(&p);
if (dd <= Sqr(tmpm1->radius + tmpm2->radius))
{
d = Sqrt(dd) + 0.0001;
dd = 10.0* Sqr(Sqr(Sqr(tmpm1->radius + tmpm2->radius) - dd));
D3MulEqu(&p, dd / d);
D3AddEqu(&tmpm2->DstateDt->DxDt, &p);
D3SubEqu(&tmpm1->DstateDt->DxDt, &p);
}
else
{
D3MulEqu(&p, 100000.0 / dd);
D3AddEqu(&tmpm2->DstateDt->DxDt, &p);
D3SubEqu(&tmpm1->DstateDt->DxDt, &p);
}
tmpm2 = tmpm2->next;
}
if (tmpm1->state->x < BORDER)
tmpm1->DstateDt->DxDt += 1000* Sqr(tmpm1->state->x - BORDER);
if (tmpm1->state->y < BORDER)
tmpm1->DstateDt->DyDt += 1000* Sqr(tmpm1->state->y - BORDER);
if (tmpm1->state->x > h - BORDER - FONT_WIDTH *6)
tmpm1->DstateDt->DxDt -= 1000 *
Sqr(tmpm1->state->x - (h - BORDER - FONT_WIDTH *6));
if (tmpm1->state->y > v - BORDER)
tmpm1->DstateDt->DyDt -= 1000* Sqr(tmpm1->state->y - (v - BORDER));
tmpm1 = tmpm1->next;
}
}
MyMass* PlaceMass(I64 nid)
{
MyMass *tmpm = CAlloc(sizeof(MyMass));
tmpm->mass = 1.0;
tmpm->drag_profile_factor = 100.0;
tmpm->radius = 5;
tmpm->nid = nid;
tmpm->gain_lst[0] = 0x7F;
MemSet(tmpm->gain_lst + 1, 0x80, (CONNECTS_NUM - 1) *sizeof(U8));
QueueInsert(tmpm, ode->last_mass);
return tmpm;
}
MyMass* FindMassByNID(I64 nid)
{
MyMass * tmpm;
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
if (tmpm->nid == nid)
return tmpm;
tmpm = tmpm->next;
}
return NULL;
}
MyMass* FindMassByXY(I64 x, I64 y)
{
I64 dd, best_dd = I64_MAX;
MyMass *tmpm, *res = NULL;
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
dd = SqrI64(tmpm->x - x) + SqrI64(tmpm->y - y);
if (dd < best_dd)
{
res = tmpm;
best_dd = dd;
}
tmpm = tmpm->next;
}
return res;
}
I64 FindConnectIndex(MyMass *tmpm, I64 nid)
{
I64 i;
for (i = 0; i < tmpm->num_connects; i++)
if (tmpm->connect_lst[i] == nid)
return i;
return -1;
}
MySpring* PlaceSpring(MyMass *tmpm1, MyMass *tmpm2)
{
MySpring *tmps = CAlloc(sizeof(MySpring));
tmps->end1 = tmpm1;
tmps->end2 = tmpm2;
tmps->const = 10;
tmps->rest_len = 0;
tmps->color = LTGRAY;
QueueInsert(tmps, ode->last_spring);
return tmps;
}
U0 RedoSprings()
{
I64 i, k;
MyMass *tmpm, *tmpm1;
MySpring * tmps;
QueueDel(&ode->next_spring, TRUE);
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
for (i = 0; i < tmpm->num_connects; i++)
{
if ((k = tmpm->connect_lst[i]) &&
(tmpm1 = FindMassByNID(k)))
{
tmps = PlaceSpring(tmpm, tmpm1);
switch (tmpm->type)
{
case AWT_MIXER:
if (!(tmpm->gain_lst[i] &0x80))
{
//If not mute
tmps->color = GREEN;
tmps->const = 100;
}
break;
case AWT_INPUT:
case AWT_SELECTOR:
case AWT_PIN_COMPLEX:
case AWT_VENDOR:
if (i == tmpm->cur_connect)
{
tmps->color = RED;
tmps->const = 100;
}
break;
}
}
}
tmpm = tmpm->next;
}
}
U0 Init()
{
ode = ODENew(0, 1e-4, ODEF_HAS_MASSES);
ode->derive = &MyDerivative;
ode->drag_v2 = 0.002;
ode->drag_v3 = 0.00001;
ode->acceleration_limit = 5e3;
QueueInsert(ode, Fs->last_ode);
}
U0 CleanUp()
{
QueueRemove(ode);
QueueDel(&ode->next_mass, TRUE);
QueueDel(&ode->next_spring, TRUE);
ODEDel(ode);
}
U0 HDCfgConnectLst(MyMass *tmpm, 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);
tmpm->connect_lst[tmpm->num_connects++] = j.u16[0];
if (i + 1 < connection_lst_len)
tmpm->connect_lst[tmpm->num_connects++] = j.u16[1];
}
}
else
{
for (i = 0; i < connection_lst_len; i += 4)
{
j = HDWriteCORBSync(cad, nid, VERB_GET_CONNECT_LST + i);
tmpm->connect_lst[tmpm->num_connects++] = j.u8[0];
if (i + 1 < connection_lst_len)
tmpm->connect_lst[tmpm->num_connects++] = j.u8[1];
if (i + 2 < connection_lst_len)
tmpm->connect_lst[tmpm->num_connects++] = j.u8[2];
if (i + 3 < connection_lst_len)
tmpm->connect_lst[tmpm->num_connects++] = j.u8[3];
}
}
}
U0 HDCfgTraverse(I64 cad, I64 nid)
{
I64 i, j;
MyMass *tmpm = PlaceMass(nid);
j = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_SUBNODE_CNT);
if (j.u16[0])
{
tmpm->type = AWT_NODE;
for (i = j.u16[1]; i < j.u16[1] + j.u16[0]; i++)
HDCfgTraverse(cad, i);
}
else
{
tmpm->audio_widget_capabilities =
HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_AUDIO_WIDGET_CAP);
tmpm->pcm_size_rates =
HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_SAMPLE_SIZE_RATE_CAP);
tmpm->in_amp_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_INPUT_AMP_CAP);
tmpm->out_amp_cap = HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_OUTPUT_AMP_CAP);
tmpm->type = tmpm->audio_widget_capabilities >> 20 &15;
switch (tmpm->type)
{
case AWT_PIN_COMPLEX:
tmpm->pin_widget_ctl =
HDWriteCORBSync(cad, nid, VERB_PIN_WIDGET_CTL_GET);
tmpm->pin_capabilities =
HDWriteCORBSync(cad, nid, VERB_GET_PARAM + P_PIN_CAP);
if (Bt(&tmpm->pin_capabilities, 0) ||
Bt(&tmpm->pin_capabilities, 2))
tmpm->pin_sense = HDWriteCORBSync(cad, nid, VERB_PIN_SENSE_GET);
HDWriteCORBSync(cad, nid, VERB_CONNECT_SEL_SET + 0x00);
break;
case AWT_INPUT:
tmpm->disabled = TRUE;
case AWT_SELECTOR:
case AWT_VENDOR:
HDWriteCORBSync(cad, nid, VERB_CONNECT_SEL_SET + 0x00);
break;
}
if (Bt(&tmpm->audio_widget_capabilities, 8))
HDCfgConnectLst(tmpm, cad, nid);
}
}
U0 HDCfgRandomizeXY()
{
I64 h = Fs->pix_width, v = Fs->pix_height;
MyMass * tmpm;
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
tmpm->x = RandU32 % (h - 2 *BORDER - FONT_WIDTH *6) + BORDER;
tmpm->y = RandU32 % (v - 2 *BORDER) + BORDER;
tmpm = tmpm->next;
}
}
U0 HDCfgPopUpInfoTask(MyMass *tmpm)
{
I64 i;
"$$FG,RED$$NID:$$FG$$0x%02X$$FG,RED$$Type:$$FG$$%Z\n",
tmpm->nid, tmpm->type, "ST_AUDIO_WIDGET_TYPES";
i = tmpm->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))
"AmpOverride,";
if (Bt(&i, 4))
"FmtOverride,";
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 = tmpm->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 = tmpm->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(&tmpm->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";
'\n';
"\n$$FG,RED$$Connection Lst:$$FG$$\n";
for (i = 0; i < tmpm->num_connects; i++)
"%02X,", tmpm->connect_lst[i];
'\n';
"\n$$FG,RED$$Gain Lst:$$FG$$\n";
for (i = 0; i < tmpm->num_connects; i++)
"%02X,", tmpm->gain_lst[i];
'\n';
switch (tmpm->type)
{
case AWT_PIN_COMPLEX:
"\n$$FG,RED$$Pin Capabilities:$$FG$$\n";
i = tmpm->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(&tmpm->pin_capabilities, 0) ||
Bt(&tmpm->pin_capabilities, 2))
tmpm->pin_sense = HDWriteCORBSync(hda.cad,
tmpm->nid, VERB_PIN_SENSE_GET);
if (Bt(&tmpm->pin_capabilities, 0))
"Impedance Measurement:%08X\n", tmpm->pin_sense &0x7FFFFFFF;
if (Bt(&tmpm->pin_capabilities, 2))
"Presence:%d\n", Bt(&tmpm->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";
tmpm->pin_widget_ctl = I64Get("Widget Ctrl (0x%02X):",
tmpm->pin_widget_ctl, 0, 0xFF);
HDWriteCORBSync(hda.cad, tmpm->nid,
VERB_PIN_WIDGET_CTL_SET + tmpm->pin_widget_ctl);
break;
case AWT_INPUT:
"Disable";
if (tmpm->disabled = YorN)
HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x00);
else
HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x20);
'\n';
break;
case AWT_OUTPUT:
"Disable";
if (tmpm->disabled = YorN)
HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x00);
else
HDWriteCORBSync(hda.cad, tmpm->nid, VERB_CHAN_STREAM_ID_SET + 0x10);
'\n';
break;
}
}
U0 HDCfgPopUpInfo(MyMass *tmpm)
{
U8 buf[STR_LEN];
StrPrint(buf,
"HDCfgPopUpInfoTask(0x%X);\"\\n\\nPress SHIFT-ESC\\n\\n\\n\\n\";View;",
tmpm);
Fs->win_inhibit |= WIF_SELF_ODE;
Fs->draw_it = NULL;
Refresh;
PopUp(buf, Fs);
Fs->win_inhibit &= ~WIF_SELF_ODE;
Fs->draw_it = &DrawIt;
}
U0 HDCfgEdLink(MyMass *tmpm_out, MyMass *tmpm_in)
{
I64 i, j;
if ((i = FindConnectIndex(tmpm_in, tmpm_out->nid)) >= 0)
{
switch (tmpm_in->type)
{
case AWT_MIXER:
MemSet(tmpm_in->gain_lst, 0x80, sizeof(U8) *CONNECTS_NUM);
tmpm_in->gain_lst[i] = 0x7F;
for (j = 0; j < tmpm_in->num_connects; j++)
HDWriteCORBSync(hda.cad, tmpm_in->nid,
VERB_AMPLIFIER_GAIN_SET + 0x7000 + tmpm_in->gain_lst[j] + j << 8);
break;
case AWT_INPUT:
case AWT_SELECTOR:
case AWT_PIN_COMPLEX:
case AWT_VENDOR:
tmpm_in->cur_connect = i;
HDWriteCORBSync(hda.cad, tmpm_in->nid, VERB_CONNECT_SEL_SET + i);
break;
}
RedoSprings;
}
}
U0 HDCfgSave()
{
CDoc *doc = DocNew;
I64 i;
MyMass * tmpm;
DocPrint(doc, "//This file was generated by "
"$$LK,\"::/TempleOS/Adam/Sound/HDCfg.ZC.Z\","
"\"FI:::/TempleOS/Adam/Sound/HDCfg.ZC\"$$\n\n"
"U0 MyHDCfg()\n{\n");
tmpm = ode->next_mass;
while (tmpm != &ode->next_mass)
{
DocPrint(doc, " //0x%02X %Z\n", tmpm->nid, tmpm->type,
"ST_AUDIO_WIDGET_TYPES");
if (tmpm->num_connects)
{
DocPrint(doc, "//Connection Lst:");
for (i = 0; i < tmpm->num_connects; i++)
{
if (i == tmpm->cur_connect)
DocPrint(doc, "*");
DocPrint(doc, "0x%02X ", tmpm->connect_lst[i]);
}
DocPrint(doc, "\n");
if (tmpm->type == AWT_MIXER)
{
DocPrint(doc, "//Gain Lst:");
for (i = 0; i < tmpm->num_connects; i++)
DocPrint(doc, "0x%02X ", tmpm->gain_lst[i]);
DocPrint(doc, "\n");
}
}
switch (tmpm->type)
{
case AWT_OUTPUT:
if (tmpm->disabled)
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_CHAN_STREAM_ID_SET+0x00);\n",
tmpm->nid);
else
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_CHAN_STREAM_ID_SET+0x10);\n",
tmpm->nid);
break;
case AWT_MIXER:
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_AMPLIFIER_GAIN_SET+0xB07F);\n",
tmpm->nid);
for (i = 0; i < tmpm->num_connects; i++)
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_AMPLIFIER_GAIN_SET+0x%04X);\n",
tmpm->nid, 0x7000 + tmpm->gain_lst[i] + i << 8);
break;
case AWT_INPUT:
if (tmpm->disabled)
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_CHAN_STREAM_ID_SET+0x00);\n",
tmpm->nid);
else
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_CHAN_STREAM_ID_SET+0x20);\n",
tmpm->nid);
goto here;
case AWT_PIN_COMPLEX:
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_PIN_WIDGET_CTL_SET+0x%02X);\n",
tmpm->nid, tmpm->pin_widget_ctl);
case AWT_SELECTOR:
case AWT_VENDOR:
here:
if (tmpm->num_connects > 1)
DocPrint(doc,
"HDWriteCORBSync(hda.cad,0x%02X,"
"VERB_CONNECT_SEL_SET+0x%02X);\n",
tmpm->nid, tmpm->cur_connect);
break;
}
DocPrint(doc, "\n");
tmpm = tmpm->next;
}
DocPrint(doc, "LBtr(&sys_semas[SEMA_SND],0);\n"
"}\n\nif (snd_dev==SD_HD_AUDIO)\n"
"MyHDCfg;\n");
StrCopy(doc->filename.name, "~/HDAudioCfg.ZC.Z");
DocWrite(doc);
DocDel(doc);
}
U0 HDCfg()
{
I64 arg1, arg2;
MyMass *tmpm1 = NULL, *tmpm2 = NULL;
if (snd_dev != SD_HD_AUDIO)
{
"HD Audio not detected\n";
return;
}
MenuPush( "File {"
" Abort(,CH_SHIFT_ESC);"
" Exit(,CH_ESC);"
"}"
"Edit {"
" Randomize(,'\n');"
" Options(,CH_SPACE);"
"}"
);
SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
DocBottom;
AutoComplete;
WinBorder;
WinMax;
DocCursor;
DocClear;
Fs->win_inhibit = WIF_SELF_MS_L | WIF_SELF_MS_R | WIG_DBL_CLICK | WIF_SELF_DOC;
Init;
HDCfgTraverse(hda.cad, 0);
HDCfgRandomizeXY;
RedoSprings;
Fs->draw_it = &DrawIt;
PopUpOk( "This is a tool to cfgure\n"
"HD Audio.It creates $$FG,RED$$~/HDAudioCfg.ZC.Z$$FG$$\n"
"which you should $$FG,GREEN$$
#include$$FG$$ in your\n"
"$$FG,RED$$~/HomeSnd.ZC.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$$~/HDAudioCfg.ZC.Z$$FG$$.\n\n"
"The $$FG,BLUE$$BLUE$$FG$$ line in the middle is microphone waveform.\n\n"
);
HDRun(TRUE, TRUE); //run input output
try
{
while (TRUE)
{
switch (MessageGet(&arg1, &arg2,
1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP | 1 << MESSAGE_KEY_DOWN))
{
case MESSAGE_MS_L_UP:
if (tmpm1 = FindMassByXY(arg1, arg2))
HDCfgPopUpInfo(tmpm1);
tmpm1 = NULL;
break;
case MESSAGE_MS_R_DOWN:
tmpm1 = FindMassByXY(arg1, arg2);
break;
case MESSAGE_MS_R_UP:
tmpm2 = FindMassByXY(arg1, arg2);
if (tmpm1 && tmpm2)
HDCfgEdLink(tmpm1, tmpm2);
break;
case MESSAGE_KEY_DOWN:
switch (arg1)
{
case CH_SPACE:
if (tmpm1 = FindMassByXY( mouse.pos.x - Fs->pix_left - Fs->scroll_x,
mouse.pos.y - Fs->pix_top - Fs->scroll_y))
HDCfgPopUpInfo(tmpm1);
tmpm1 = 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
MessageGet(,, 1 << MESSAGE_KEY_UP);
}
catch
Fs->catch_except = TRUE;
SettingsPop;
HDStop(TRUE, FALSE); //stop input
CleanUp;
MenuPop;
"$$BK,1$$Note:
#include \"~/HDAudioCfg\" in your start-up scripts."
"$$BK,0$$\n";
}
HDCfg;

View file

@ -0,0 +1,21 @@
Cd(__DIR__);;
#help_index "Sound"
class CSndWaveCtrl
{
I64 sample_rate,sample_bits,channels;
F64 freq_multiplier,amp_multiplier;
F64 phase,last_y,last_dydt,next_y;
};
public U0 SoundTaskEndCB()
{//Will turn-off snd when a task gets killed.
Sound;
Exit;
}
#include "SndMath"
#include "SndMusic"
#include "SndEffects"
#include "SndFile"
Cd("..");;

View file

@ -0,0 +1,80 @@
#help_index "Sound"
#define SE_NOISE 0
#define SE_SWEEP 1
class CSoundEffectFrame
{
I32 type;
I8 ona1,ona2;
F64 duration;
};
U0 SoundEffectEndTaskCB()
{
Free(FramePtr("CSoundEffectFrame"));
music.mute--;
SoundTaskEndCB;
}
U0 SoundEffectTask(CSoundEffectFrame *ns)
{
I64 i,ona;
F64 t0=tS,t,timeout=t0+ns->duration;
FramePtrAdd("CSoundEffectFrame",ns);
Fs->task_end_cb=&SoundEffectEndTaskCB;
switch (ns->type) {
case SE_NOISE:
i=MaxI64(ns->ona2-ns->ona1,1);
while (tS<timeout) {
ona=RandU16%i+ns->ona1;
Sound(ona);
t=Clamp(3000.0/Ona2Freq(ona),1.0,50.0);
if (t+tS>timeout)
t=timeout-tS;
Sleep(t);
}
break;
case SE_SWEEP:
while (tS<timeout) {
t=(tS-t0)/ns->duration;
ona=(1.0-t)*ns->ona1+t*ns->ona2;
Sound(ona);
t=Clamp(3000.0/Ona2Freq(ona),1.0,50.0);
if (t+tS>timeout)
t=timeout-tS;
Sleep(t);
}
break;
}
}
public CTask *Noise(I64 mS,F64 min_ona,F64 max_ona)
{//Make white noise for given number of mS.
CSoundEffectFrame *ns;
if (mS>0) {
ns=MAlloc(sizeof(CSoundEffectFrame));
ns->type=SE_NOISE;
ns->duration=mS/1000.0;
ns->ona1=min_ona;
ns->ona2=max_ona;
music.mute++;
return Spawn(&SoundEffectTask,ns,"Noise",,Fs);
} else
return NULL;
}
public CTask *Sweep(I64 mS,F64 ona1,F64 ona2)
{//Sweep through freq range in given number of mS.
CSoundEffectFrame *ns;
if (mS>0) {
ns=MAlloc(sizeof(CSoundEffectFrame));
ns->type=SE_SWEEP;
ns->duration=mS/1000.0;
ns->ona1=ona1;
ns->ona2=ona2;
music.mute++;
return Spawn(&SoundEffectTask,ns,"Noise",,Fs);
} else
return NULL;
}

View file

@ -0,0 +1,137 @@
#help_index "Sound/Sound 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];
};
//Windows media constraint.
//#define SND_FILE_DATA_MAX 0x0007FF00
#define SND_FILE_DATA_MAX 0x7FFFFF00
public I64 SndFileCreate(U8 *base_filename,F64 normalized_vol=1.0,
F64 averaging=0.0,I64 waveform=WF_SQUARE,
F64 reverb_delay=0,F64 reverb_intensity=0,F64 time_shift=0)
{//Use "screencast.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.
//Set reverb_delay to like 0.3 sec and reverb_intensity to like 0.4.
I64 i,i1,k,cnt,cnt2,level,file_num;
F64 avg,dt;
CFileSND *s;
CSndWaveCtrl *swc=SndWaveCtrlNew(SNDFILE_SAMPLE_RATE,16,1);
CSoundData *d,*d1;
U8 *name,*name2;
screencast.record=FALSE;
dt=screencast.sound_head.last->tS-screencast.sound_head.next->tS;
if (!dt) return 0;
cnt=dt*SNDFILE_SAMPLE_RATE;
cnt++; //Terminator
name=StrNew(base_filename);
FileExtRemove(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);
if (time_shift) {
d=screencast.sound_head.next;
d->tS-=time_shift;
while (d->next!=&screencast.sound_head) {
d1=d->next;
dt=d1->tS-d->tS;
if (dt<0) {
QueueRemove(d1);
Free(d1);
} else
break;
}
}
d=screencast.sound_head.next;
k=0;
i=d->tS*SNDFILE_SAMPLE_RATE;
while (d->next!=&screencast.sound_head) {
d1=d->next;
i1=d1->tS*SNDFILE_SAMPLE_RATE;
if (i1-i) {
SndWaveAddBuf(swc,&s->body[k],i1-i,
Ona2Freq(d->ona),waveform,normalized_vol);
k+=i1-i;
i=i1;
}
QueueRemove(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]=ClampI64(s->body[i]-level,I16_MIN,I16_MAX);
}
for (i=0;i<cnt-1;i++)
s->body[i]=EndianU16(s->body[i]);
s->body[cnt-1]=0;
d=screencast.sound_head.next;
while (d!=&screencast.sound_head) {
d1=d->next;
QueueRemove(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>SND_FILE_DATA_MAX)
i=SND_FILE_DATA_MAX;
s->data_size=EndianU32(i*sizeof(I16));
MemCopy(s->body,&s->body[file_num*SND_FILE_DATA_MAX],i*sizeof(I16));
StrPrint(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;
}

View file

@ -0,0 +1,248 @@
#help_index "Sound/Math;Math"
public F64 Saw(F64 t,F64 period)
{//Sawtooth. 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)
{//Plus&Minus Sawtooth. 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)
{//Cawtooth. 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)
{//Plus&Minus Cawtooth. 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)
{//Triangle waveform. 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)
{//Plus&Minus Triangle waveform. 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 "Sound/Math"
public I8 Note2Ona(I64 note,I64 octave=4)
{//Note to ona. Mid C is ona=51, note=3 and octave=4.
if (note<3)
return (octave+1)*12+note;
else
return octave*12+note;
}
public I8 Ona2Note(I8 ona)
{//Ona to note in octave. Mid C is ona=51, note=3 and octave=4.
return ona%12;
}
public I8 Ona2Octave(I8 ona)
{//Ona to octave. Mid C is ona=51, note=3 and octave=4.
I64 note=ona%12,octave=ona/12;
if (note<3)
return octave-1;
else
return octave;
}
F64 SinPhaseCont(F64 last_y,F64 last_dydt,
F64 current_amp,F64 phase_offset)
{//Next sample of sin waveform.
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=8000,I64 sample_bits=24,
I64 channels=2,CTask *mem_task=NULL)
{//MAlloc ctrl struct for generating waveforms.
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 waveform ctrl.
Free(swc);
}
#define WF_NULL 0
#define WF_SQUARE 1
#define WF_SINE 2
#define WF_TRI 3
#define WF_SAWTOOTH 4
#define WF_NOISE 5
#define WF_WAVEFORMS_NUM 6
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)
{//Add waveform to buffer.
//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(I32_MAX,I32_MAX*_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_TRI:
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/U16_MAX;
}
j=swc->last_y*(ã-phase)+swc->next_y*phase;
} else {
if (phase-ã<f) {
swc->last_y=swc->next_y;
swc->next_y=a*RandI16/U16_MAX;
}
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;
}
}

View file

@ -0,0 +1,224 @@
#help_index "Sound/Music"
public class CMusicGlbls
{
U8 *cur_song;
CTask *cur_song_task;
I64 octave;
F64 note_len;
U8 note_map[7];
Bool mute;
I64 meter_top,meter_bottom;
F64 tempo,stacatto_factor;
//If you wish to sync with a
//note in a Play() string. 0 is the start
I64 play_note_num;
F64 tM_correction,last_Beat,last_tM;
} music={NULL,NULL,4,1.0,{0,2,3,5,7,8,10},FALSE,4,4,2.5,0.9,0,0,0,0};
#help_index "Sound/Music;Time/Seconds"
public F64 tM()
{//Time in seconds synced to music subsystem.
return (counts.jiffies+music.tM_correction)/JIFFY_FREQ;
}
public F64 Beat()
{//Time in music beats.
F64 res,cur_tM;
PUSHFD
CLI
if (mp_count>1)
while (LBts(&sys_semas[SEMA_TMBEAT],0))
PAUSE
cur_tM=tM;
res=music.last_Beat;
if (music.tempo)
res+=(cur_tM-music.last_tM)*music.tempo;
music.last_tM=cur_tM;
music.last_Beat=res;
LBtr(&sys_semas[SEMA_TMBEAT],0);
POPFD
return res;
}
#help_index "Sound/Music"
U8 *MusicSetOctave(U8 *st)
{
I64 ch;
ch=*st++;
while ('0'<=ch<='9') {
music.octave=ch-'0';
ch=*st++;
}
return --st;
}
U8 *MusicSetMeter(U8 *st)
{
I64 ch;
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. Mid C is octave 4.
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
$LK,"music.meter_top",A="MN:CMusicGlbls"$,$LK,"music.meter_bottom",A="MN:CMusicGlbls"$ 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.tempo is quarter-notes
per second.It defaults to
2.5 and gets faster when bigger.
*/
U8 *word,*last_st;
I64 note,octave,i=0,ona,timeout_val,timeout_val2;
Bool tie;
F64 d,on_jiffies,off_jiffies;
music.play_note_num=0;
while (*st) {
timeout_val=counts.jiffies;
tie=FALSE;
do {
last_st=st;
if (*st=='(') {
tie=TRUE;
st++;
} else {
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];
octave=music.octave;
if (*st=='b') {
note--;
if (note==2)
octave--;
st++;
} else if (*st=='#') {
note++;
if (note==3)
octave++;
st++;
}
ona=Note2Ona(note,octave);
} else
ona=0;
if (words && (word=ListSub(i++,words)) && StrCompare(word,""))
"%s",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)
Sound(ona);
SleepUntil(timeout_val);
music.tM_correction+=on_jiffies-ToI64(on_jiffies);
if (!music.mute)
Sound;
SleepUntil(timeout_val2);
music.tM_correction+=off_jiffies-ToI64(off_jiffies);
music.play_note_num++;
}
}
U0 MusicSettingsReset()
{
music.play_note_num=0;
music.stacatto_factor=0.9;
music.tempo=2.5;
music.octave=4;
music.note_len=1.0;
music.meter_top=4;
music.meter_bottom=4;
SoundReset;
PUSHFD
CLI
if (mp_count>1)
while (LBts(&sys_semas[SEMA_TMBEAT],0))
PAUSE
music.last_tM=tM;
music.last_Beat=0.0;
LBtr(&sys_semas[SEMA_TMBEAT],0);
POPFD
}
MusicSettingsReset;
U0 CurSongTask()
{
Fs->task_end_cb=&SoundTaskEndCB;
while (TRUE)
Play(music.cur_song);
}