mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-25 23:10:32 +00:00
init
This commit is contained in:
parent
b32f9cea77
commit
5055a3b7f8
14 changed files with 1161 additions and 0 deletions
21
src/Home/Tracker/Classes.ZC
Normal file
21
src/Home/Tracker/Classes.ZC
Normal file
|
@ -0,0 +1,21 @@
|
|||
class NoteCell {
|
||||
U8 note; // MIDI note number
|
||||
U8 velocity; // Volume/Intensity
|
||||
U8 instrument;
|
||||
U8 effect; // Future expansion for effects
|
||||
};
|
||||
|
||||
#define TRACK_LENGTH 64 // Length of each pattern in rows
|
||||
class Pattern {
|
||||
NoteCell cells[TRACK_LENGTH];
|
||||
};
|
||||
|
||||
#define MAX_PATTERNS 64 // Maximum patterns in a song
|
||||
class Song {
|
||||
U8 patternOrder[MAX_PATTERNS]; // Which pattern is played when
|
||||
Pattern patterns[MAX_PATTERNS];
|
||||
};
|
||||
|
||||
|
||||
#define SAMPLE_RATE 44100
|
||||
#define PI 3.1415926535897932 // i know i can just use the pi symbol
|
240
src/Home/Tracker/Lib/AC97.ZC
Executable file
240
src/Home/Tracker/Lib/AC97.ZC
Executable file
|
@ -0,0 +1,240 @@
|
|||
|
||||
#define INT_LAST_VALID_ENTRY 1 << 2
|
||||
#define INT_IOC 1 << 3
|
||||
#define INT_FIFO_ERR 1 << 4
|
||||
|
||||
#define BDL_BUF_SIZE 2044
|
||||
#define MAX_BDLS 32
|
||||
|
||||
#define PCM_BUF_SIZE 2048
|
||||
#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 CAC97BufferDescriptorListEntry
|
||||
{
|
||||
U32 addr;
|
||||
U16 length; // length - 1
|
||||
U16 flags;
|
||||
};
|
||||
|
||||
class CAC97BufferDescriptorList
|
||||
{
|
||||
CAC97BufferDescriptorListEntry entries[32];
|
||||
};
|
||||
|
||||
class CAC97
|
||||
{
|
||||
CPCIInfo pci;
|
||||
CAC97BufferDescriptorList *bdl[3];
|
||||
U16 nam;
|
||||
U16 nabm;
|
||||
};
|
||||
|
||||
CAC97 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 CAudioStream
|
||||
{
|
||||
CFifoI64 *data;
|
||||
};
|
||||
|
||||
class CAudio
|
||||
{
|
||||
CAudioStream output[AUDIO_MAX_STREAMS];
|
||||
I64 output_frames[AUDIO_MAX_STREAMS];
|
||||
};
|
||||
|
||||
CAudio audio;
|
||||
|
||||
U0 AudioInit()
|
||||
{
|
||||
I64 i = 0;
|
||||
for (i = 0; i < AUDIO_MAX_STREAMS; i++)
|
||||
audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE, sys_task);
|
||||
}
|
||||
|
||||
AudioInit;
|
||||
|
||||
I64 AudioAvailableOutputStreamGet()
|
||||
{
|
||||
I64 stream = 0;
|
||||
while (FifoI64Count(audio.output[stream].data))
|
||||
stream++;
|
||||
if (stream > AUDIO_MAX_STREAMS - 1)
|
||||
return -1;
|
||||
return stream;
|
||||
}
|
||||
|
||||
I64 AudioSFXPlay(U32 *data, I64 length)
|
||||
{
|
||||
I64 i;
|
||||
I64 stream = AudioAvailableOutputStreamGet;
|
||||
if (stream < 0)
|
||||
return stream;
|
||||
for (i = 0; i < length; i++)
|
||||
FifoI64Ins(audio.output[stream].data, data[i]);
|
||||
return stream;
|
||||
}
|
||||
|
||||
U0 AC97OutputMix(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 AC97BufferFill()
|
||||
{
|
||||
I64 idx = InU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY);
|
||||
U32 *buf = ac97.bdl[PCM_OUT]->entries[idx].addr;
|
||||
AC97OutputMix(buf, BDL_BUF_SIZE);
|
||||
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx);
|
||||
}
|
||||
|
||||
U0 AC97AudioProcess()
|
||||
{
|
||||
U16 status = InU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS);
|
||||
if (status & INT_IOC)
|
||||
{
|
||||
AC97BufferFill;
|
||||
OutU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C);
|
||||
}
|
||||
}
|
||||
|
||||
I64 AC97Init()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
PCIInfoGet(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(CAC97BufferDescriptorList), 4096, Fs->code_heap);
|
||||
ac97.bdl[PCM_OUT] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
|
||||
ac97.bdl[MIC_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 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
|
||||
AC97BufferFill;
|
||||
|
||||
// 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 AC97Task()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
AC97AudioProcess;
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
AC97Init;
|
||||
Spawn(&AC97Task,, "AC97 Task", 1);
|
21
src/Home/Tracker/Lib/Debug.ZC
Executable file
21
src/Home/Tracker/Lib/Debug.ZC
Executable file
|
@ -0,0 +1,21 @@
|
|||
class Debug {
|
||||
Bool enabled;
|
||||
I64 bookmark;
|
||||
I64 counter;
|
||||
};
|
||||
|
||||
Debug debug;
|
||||
debug.bookmark = 0;
|
||||
debug.counter = 0;
|
||||
debug.enabled = FALSE;
|
||||
|
||||
U0 debug_print(U8 *fmt, ...) {
|
||||
if (!debug.enabled || debug.counter < debug.bookmark) {
|
||||
debug.counter++;
|
||||
return;
|
||||
}
|
||||
U8 *buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
"[%05d] %s", debug.counter, buf;
|
||||
Free(buf);
|
||||
debug.counter++;
|
||||
}
|
355
src/Home/Tracker/Lib/ELF64.ZC
Executable file
355
src/Home/Tracker/Lib/ELF64.ZC
Executable file
|
@ -0,0 +1,355 @@
|
|||
#define EI_NIDENT 16
|
||||
#define EM_X86_64 0x3E
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
|
||||
class Elf64_Ehdr {
|
||||
U8 e_ident[EI_NIDENT]; /* Magic number and other info */
|
||||
U16 e_type; /* Object file type */
|
||||
U16 e_machine; /* Architecture */
|
||||
U32 e_version; /* Object file version */
|
||||
U64 e_entry; /* Entry point virtual address */
|
||||
U64 e_phoff; /* Program header table file offset */
|
||||
U64 e_shoff; /* Section header table file offset */
|
||||
U32 e_flags; /* Processor-specific flags */
|
||||
U16 e_ehsize; /* ELF header size in bytes */
|
||||
U16 e_phentsize; /* Program header table entry size */
|
||||
U16 e_phnum; /* Program header table entry count */
|
||||
U16 e_shentsize; /* Section header table entry size */
|
||||
U16 e_shnum; /* Section header table entry count */
|
||||
U16 e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
class Elf64_Shdr {
|
||||
U32 sh_name; /* Section name (string tbl index) */
|
||||
U32 sh_type; /* Section type */
|
||||
U64 sh_flags; /* Section flags */
|
||||
U64 sh_addr; /* Section virtual addr at execution */
|
||||
U64 sh_offset; /* Section file offset */
|
||||
U64 sh_size; /* Section size in bytes */
|
||||
U32 sh_link; /* Link to another section */
|
||||
U32 sh_info; /* Additional section information */
|
||||
U64 sh_addralign; /* Section alignment */
|
||||
U64 sh_entsize; /* Entry size if section holds table */
|
||||
};
|
||||
|
||||
class Elf64_Sym {
|
||||
U32 st_name; /* Symbol name (string tbl index) */
|
||||
U8 st_info; /* Symbol type and binding */
|
||||
U8 st_other; /* Symbol visibility */
|
||||
U16 st_shndx; /* Section index */
|
||||
U64 st_value; /* Symbol value */
|
||||
U64 st_size; /* Symbol size */
|
||||
};
|
||||
|
||||
class PLT_entry {
|
||||
U8 pad[0x10];
|
||||
};
|
||||
|
||||
class RELA_entry {
|
||||
U64 r_offset;
|
||||
U64 r_info;
|
||||
I64 r_addend;
|
||||
};
|
||||
|
||||
class Elf {
|
||||
union {
|
||||
U8 *u8;
|
||||
Elf64_Ehdr *ehdr;
|
||||
} I64 size;
|
||||
U8 *dynstr;
|
||||
Elf64_Sym *dynsym;
|
||||
PLT_entry *plt;
|
||||
RELA_entry *rela_dyn;
|
||||
RELA_entry *rela_plt;
|
||||
Elf64_Sym *strtab;
|
||||
Elf64_Sym *symtab;
|
||||
I64 rela_dyn_size;
|
||||
I64 rela_plt_size;
|
||||
I64 strtab_size;
|
||||
I64 symtab_size;
|
||||
};
|
||||
|
||||
U0 (*_start)();
|
||||
|
||||
U0 unimplemented_symbol() {
|
||||
I32 s = 0xDEADF00D;
|
||||
"Unimplemented symbol: %s\n", s;
|
||||
while (1)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
Bool is_valid_elf(Elf *elf) {
|
||||
Bool res = TRUE;
|
||||
if (MemCompare(elf->u8 + 1, "ELF", 3)) {
|
||||
debug_print("Invalid signature (not ELF).\n");
|
||||
res = FALSE;
|
||||
}
|
||||
if (elf->ehdr->e_type != ET_EXEC && elf->ehdr->e_type != ET_DYN) {
|
||||
debug_print("Invalid object file type.\n");
|
||||
res = FALSE;
|
||||
}
|
||||
if (elf->ehdr->e_machine != EM_X86_64) {
|
||||
debug_print("Invalid architecture.\n");
|
||||
res = FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 find_value(U8 *value) {
|
||||
U64 addr = 0x0;
|
||||
while (addr < 0x2000000) {
|
||||
if (!MemCompare(addr, value, StrLen(value))) {
|
||||
"found at 0x%08x\n", addr;
|
||||
return;
|
||||
}
|
||||
addr++;
|
||||
}
|
||||
"not found\n";
|
||||
}
|
||||
|
||||
U0 process_elf_section_header_table(Elf *elf) {
|
||||
Elf64_Shdr *shdr = elf->u8 + elf->ehdr->e_shoff;
|
||||
Elf64_Shdr *shdr_shstrtab = shdr + elf->ehdr->e_shstrndx;
|
||||
U8 *shstrtab = elf->u8 + shdr_shstrtab->sh_offset;
|
||||
I64 i = 0;
|
||||
while (i < elf->ehdr->e_shnum) {
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".symtab")) {
|
||||
debug_print("found symtab at 0x%08x, size = %d\n", shdr->sh_offset,
|
||||
shdr->sh_size);
|
||||
elf->symtab = elf->u8 + shdr->sh_offset;
|
||||
elf->symtab_size = shdr->sh_size;
|
||||
}
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".strtab")) {
|
||||
debug_print("found strtab at 0x%08x, size = %d\n", shdr->sh_offset,
|
||||
shdr->sh_size);
|
||||
elf->strtab = elf->u8 + shdr->sh_offset;
|
||||
elf->strtab_size = shdr->sh_size;
|
||||
}
|
||||
if (shdr->sh_addr) {
|
||||
MemCopy(shdr->sh_addr, elf->u8 + shdr->sh_offset, shdr->sh_size);
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".dynstr"))
|
||||
elf->dynstr = shdr->sh_addr;
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".dynsym"))
|
||||
elf->dynsym = shdr->sh_addr;
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".plt"))
|
||||
elf->plt = shdr->sh_addr;
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".rela.dyn")) {
|
||||
elf->rela_dyn = shdr->sh_addr;
|
||||
elf->rela_dyn_size = shdr->sh_size / shdr->sh_entsize;
|
||||
}
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".rela.plt")) {
|
||||
elf->rela_plt = shdr->sh_addr;
|
||||
elf->rela_plt_size = shdr->sh_size / shdr->sh_entsize;
|
||||
}
|
||||
debug_print(
|
||||
"MemCopy section '%s' to physical address 0x%06x, size = %d bytes\n",
|
||||
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
|
||||
if (!StrCompare(shstrtab + shdr->sh_name, ".bss")) {
|
||||
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
|
||||
debug_print("MemSet section '%s' at physical address 0x%06x to NULL, "
|
||||
"size = %d bytes\n",
|
||||
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
|
||||
}
|
||||
}
|
||||
shdr++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 process_elf_rela_dyn_entries(Elf *elf) {
|
||||
I64 i;
|
||||
U8 *entry_name;
|
||||
RELA_entry *rela_dyn = elf->rela_dyn;
|
||||
for (i = 0; i < elf->rela_dyn_size; i++) {
|
||||
entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name;
|
||||
debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset);
|
||||
debug_print("entry name = '%s'\n", entry_name);
|
||||
if (!StrCompare(entry_name, "__libc_start_main")) {
|
||||
*(rela_dyn->r_offset)(U64 *) = &_main;
|
||||
debug_print("Set value for .rela.dyn entry '%s' to: &_main\n",
|
||||
entry_name);
|
||||
}
|
||||
if (!StrCompare(entry_name, "stdin")) {
|
||||
*(rela_dyn->r_offset)(U64 *) = 0;
|
||||
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0);
|
||||
}
|
||||
if (!StrCompare(entry_name, "stdout")) {
|
||||
*(rela_dyn->r_offset)(U64 *) = 1;
|
||||
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 1);
|
||||
}
|
||||
if (!StrCompare(entry_name, "stderr")) {
|
||||
*(rela_dyn->r_offset)(U64 *) = 2;
|
||||
debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 2);
|
||||
}
|
||||
rela_dyn++;
|
||||
}
|
||||
}
|
||||
|
||||
CHashClass *get_symbol_hash_entry(U8 *entry_name) {
|
||||
I64 i;
|
||||
CHashSrcSym *sym;
|
||||
CHashTable *tbl = Fs->hash_table;
|
||||
while (tbl) {
|
||||
for (i = 0; i < tbl->mask; i++) {
|
||||
sym = tbl->body[i];
|
||||
while (sym) {
|
||||
if (sym->type == HTT_CLASS)
|
||||
if (!StrCompare(sym->str, entry_name))
|
||||
return sym;
|
||||
sym = sym->next;
|
||||
}
|
||||
}
|
||||
tbl = tbl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 process_elf_debug_symbols(Elf *elf) {
|
||||
I64 i = 0;
|
||||
I64 entry_bind;
|
||||
U64 entry_name;
|
||||
I64 entry_type;
|
||||
CHashFun *hf;
|
||||
CHashGlobalVar *hgv;
|
||||
Elf64_Sym *symtab = elf->symtab;
|
||||
entry_name = elf->strtab;
|
||||
entry_name += symtab->st_name;
|
||||
while (i < 253) {
|
||||
entry_bind = symtab->st_info >> 4;
|
||||
entry_type = symtab->st_info & 0xf;
|
||||
switch (entry_type) {
|
||||
case STT_OBJECT:
|
||||
hgv = CAlloc(sizeof(CHashGlobalVar));
|
||||
hgv->str = entry_name;
|
||||
hgv->type = HTT_GLOBAL_VAR;
|
||||
hgv->data_addr = symtab->st_value;
|
||||
hgv->size = symtab->st_size;
|
||||
// TempleOS reboots if I nest a switch table here, for some reason, so we
|
||||
// have to do this dumb shit instead...
|
||||
hgv->var_class = get_symbol_hash_entry("U32");
|
||||
if (hgv->size == 1)
|
||||
hgv->var_class = get_symbol_hash_entry("U8");
|
||||
if (hgv->size == 2)
|
||||
hgv->var_class = get_symbol_hash_entry("U16");
|
||||
HashAdd(hgv, Fs->hash_table);
|
||||
debug_print(
|
||||
"Add global variable '%s' to hash table, addr = 0x%08x, size = %d\n",
|
||||
entry_name, symtab->st_value, symtab->st_size);
|
||||
break;
|
||||
case STT_FUNC:
|
||||
hf = CAlloc(sizeof(CHashFun));
|
||||
hf->str = entry_name;
|
||||
hf->type = HTT_FUN;
|
||||
hf->exe_addr = symtab->st_value;
|
||||
hf->size = symtab->st_size;
|
||||
HashAdd(hf, Fs->hash_table);
|
||||
debug_print("Add function '%s' to hash table, addr = 0x%08x, size = %d\n",
|
||||
entry_name, symtab->st_value, symtab->st_size);
|
||||
break;
|
||||
}
|
||||
symtab++;
|
||||
i++;
|
||||
entry_name = elf->strtab;
|
||||
entry_name += symtab->st_name;
|
||||
}
|
||||
}
|
||||
|
||||
U64 get_symbol_address(U8 *entry_name) {
|
||||
I64 i;
|
||||
CHashSrcSym *sym;
|
||||
CHashTable *tbl = Fs->hash_table;
|
||||
while (tbl) {
|
||||
for (i = 0; i < tbl->mask; i++) {
|
||||
sym = tbl->body[i];
|
||||
while (sym) {
|
||||
if (sym->type == HTT_GLOBAL_VAR)
|
||||
if (!StrCompare(sym->str, entry_name))
|
||||
return sym(CHashGlobalVar *)->data_addr;
|
||||
if (sym->type == HTT_FUN)
|
||||
if (!StrCompare(sym->str, entry_name))
|
||||
return sym(CHashFun *)->exe_addr;
|
||||
sym = sym->next;
|
||||
}
|
||||
}
|
||||
tbl = tbl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 process_debug_patches(Elf *elf) { no_warn elf; }
|
||||
|
||||
U0 process_elf_rela_plt_entries(Elf *elf) {
|
||||
I64 i;
|
||||
U32 handler;
|
||||
U32 *patch;
|
||||
U8 *entry_name;
|
||||
Bool symbol_exists;
|
||||
PLT_entry *plt = elf->plt;
|
||||
RELA_entry *rela_plt = elf->rela_plt;
|
||||
plt++;
|
||||
for (i = 0; i < elf->rela_plt_size; i++) {
|
||||
symbol_exists = FALSE;
|
||||
entry_name = elf->dynstr + elf->dynsym[(rela_plt->r_info >> 32)].st_name;
|
||||
handler = MAlloc(sizeof(unimplemented_symbol), Fs->code_heap);
|
||||
MemCopy(handler, &unimplemented_symbol, sizeof(unimplemented_symbol));
|
||||
patch = handler + 0x0A;
|
||||
*patch = entry_name;
|
||||
PatchJmpRel32(plt, handler);
|
||||
PatchCallRel32(handler + 0x16, &PrintErr);
|
||||
PatchCallRel32(handler + 0x21, &_exit);
|
||||
if (!StrCompare(entry_name, "__libc_start_main")) {
|
||||
symbol_exists = TRUE;
|
||||
PatchJmpRel32(plt, &_main);
|
||||
debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name);
|
||||
}
|
||||
if (get_symbol_address(entry_name)) {
|
||||
symbol_exists = TRUE;
|
||||
PatchJmpRel32(plt, get_symbol_address(entry_name));
|
||||
debug_print("Set value for .rela.plt entry '%s' to &%s\n", entry_name,
|
||||
entry_name);
|
||||
}
|
||||
if (!symbol_exists)
|
||||
debug_print(
|
||||
"Set value for .rela.plt entry '%s' to &unimplemented_symbol\n",
|
||||
entry_name);
|
||||
rela_plt++;
|
||||
plt++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 load_elf(...) {
|
||||
if (argc < 1) {
|
||||
PrintErr("Not enough arguments.\n");
|
||||
return;
|
||||
}
|
||||
if (!FileFind(argv[0])) {
|
||||
PrintErr("File not found: %s\n", argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
Elf elf;
|
||||
elf.u8 = FileRead(argv[0], &elf.size);
|
||||
debug_print("Load file '%s', size = %d bytes\n", argv[0], elf.size);
|
||||
|
||||
if (!is_valid_elf(&elf)) {
|
||||
PrintErr("File is not a valid ELF x86-64 executable.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
process_elf_section_header_table(&elf);
|
||||
process_elf_rela_dyn_entries(&elf);
|
||||
process_elf_rela_plt_entries(&elf);
|
||||
process_elf_debug_symbols(&elf);
|
||||
|
||||
_start = elf.ehdr->e_entry;
|
||||
elf_argc = argc;
|
||||
elf_argv = argv;
|
||||
|
||||
process_debug_patches(&elf);
|
||||
|
||||
//_start();
|
||||
}
|
151
src/Home/Tracker/Lib/LibC.ZC
Executable file
151
src/Home/Tracker/Lib/LibC.ZC
Executable file
|
@ -0,0 +1,151 @@
|
|||
U64 find_u32_in_memory(U64 offset, U32 value) {
|
||||
I64 i = 0;
|
||||
while (MemCompare(offset + i, &value, 4))
|
||||
i++;
|
||||
return offset + i;
|
||||
}
|
||||
|
||||
#define PUSH_SYSV_REGS \
|
||||
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
|
||||
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
|
||||
#define POP_SYSV_REGS \
|
||||
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
|
||||
RSI POP RBP POP RBX POP RDX POP RCX}
|
||||
#define MOV_ANS_RAX asm {MOV [&ans], RAX}
|
||||
#define MOV_P0_RDI asm {MOV [&p0], RDI}
|
||||
#define MOV_P1_RSI asm {MOV [&p1], RSI}
|
||||
#define MOV_P2_RDX asm {MOV [&p2], RDX}
|
||||
#define MOV_P3_RCX asm {MOV [&p3], RCX}
|
||||
#define MOV_P4_R8 asm {MOV [&p4], R8}
|
||||
#define MOV_P5_R9 asm {MOV [&p5], R9}
|
||||
#define GET_SYSV_ARGS \
|
||||
MOV_P0_RDI MOV_P1_RSI MOV_P2_RDX MOV_P3_RCX MOV_P4_R8 MOV_P5_R9
|
||||
|
||||
I64 p0, p1, p2, p3, p4, p5;
|
||||
I64 elf_argc;
|
||||
U8 **elf_argv;
|
||||
|
||||
#define stdin 0
|
||||
#define stdout 1
|
||||
#define stderr 2
|
||||
|
||||
asm {
|
||||
_ELF_CALL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
MOV RSI,U64 SF_ARG3[RBP]
|
||||
TEST RAX,RAX
|
||||
JZ @@05
|
||||
CALL RAX
|
||||
@@05: POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
U0 _main() {
|
||||
MOV_P0_RDI
|
||||
CallInd(_ELF_CALL, p0, elf_argc, elf_argv);
|
||||
MOV_ANS_RAX
|
||||
throw('end', TRUE);
|
||||
}
|
||||
|
||||
U0 _exit() {
|
||||
MOV_ANS_RAX
|
||||
throw('end', TRUE);
|
||||
}
|
||||
|
||||
U0 free() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called free(0x%08x)\n", p0);
|
||||
Free(p0);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U64 @malloc(I64 size) {
|
||||
U64 ptr = NULL;
|
||||
ptr = MAlloc(p0);
|
||||
debug_print("malloc(%d), result: 0x%08x\n", size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
U0 malloc() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called: malloc(%d)\n", p0);
|
||||
@malloc(p0);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U0 memcpy() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called: memcpy(0x%08x, 0x%08x, %d)\n", p0, p1, p2);
|
||||
MemCopy(p0, p1, p2);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U8 *@memmove(U8 *dest, U8 *src, I64 n) {
|
||||
I64 i;
|
||||
U8 *from = src;
|
||||
U8 *to = dest;
|
||||
if (from == to || n == 0)
|
||||
return dest;
|
||||
if (to > from && to - from < n) {
|
||||
/* to overlaps with from */
|
||||
/* <from......> */
|
||||
/* <to........> */
|
||||
/* copy in reverse, to avoid overwriting from */
|
||||
for (i = n - 1; i >= 0; i--)
|
||||
to[i] = from[i];
|
||||
return dest;
|
||||
}
|
||||
if (from > to && from - to < n) {
|
||||
/* to overlaps with from */
|
||||
/* <from......> */
|
||||
/* <to........> */
|
||||
/* copy forwards, to avoid overwriting from */
|
||||
for (i = 0; i < n; i++)
|
||||
to[i] = from[i];
|
||||
return dest;
|
||||
}
|
||||
MemCopy(dest, src, n);
|
||||
return dest;
|
||||
}
|
||||
|
||||
U0 memmove() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called: memmove(0x%08x, 0x%08x, %d)\n", p0, p1, p2);
|
||||
@memmove(p0, p1, p2);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U0 memset() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called: memset(0x%08x, %d, %d)\n", p0, p1, p2);
|
||||
MemSet(p0, p1, p2);
|
||||
POP_SYSV_REGS
|
||||
}
|
||||
|
||||
U8 *@realloc(U8 *ptr, I64 size) {
|
||||
U8 *new;
|
||||
if (!ptr) {
|
||||
new = MAlloc(size);
|
||||
} else {
|
||||
new = MAlloc(size);
|
||||
MemCopy(new, ptr, size);
|
||||
Free(ptr);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
U0 realloc() {
|
||||
PUSH_SYSV_REGS
|
||||
GET_SYSV_ARGS
|
||||
debug_print("called: realloc(0x%08x, %d)\n", p0, p1);
|
||||
@realloc(p0, p1);
|
||||
POP_SYSV_REGS
|
||||
}
|
16
src/Home/Tracker/Lib/LibHolyC.ZC
Executable file
16
src/Home/Tracker/Lib/LibHolyC.ZC
Executable file
|
@ -0,0 +1,16 @@
|
|||
asm {
|
||||
GCC_FUN_ADDR::
|
||||
DU64 0;
|
||||
HOLYC_ARG1::
|
||||
DU64 0;
|
||||
HOLYC_ARG2::
|
||||
DU64 0;
|
||||
HOLYC_ARG3::
|
||||
DU64 0;
|
||||
HOLYC_ARG4::
|
||||
DU64 0;
|
||||
HOLYC_ARG5::
|
||||
DU64 0;
|
||||
HOLYC_ARG6::
|
||||
DU64 0;
|
||||
}
|
30
src/Home/Tracker/Lib/Misc.ZC
Executable file
30
src/Home/Tracker/Lib/Misc.ZC
Executable file
|
@ -0,0 +1,30 @@
|
|||
I64 Cond(Bool cond, I64 true, I64 false) {
|
||||
if (cond)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
U0 PatchCallRel32(U32 from, U32 to) {
|
||||
*(from(U8 *)) = 0xE8;
|
||||
*((from + 1)(I32 *)) = to - from - 5;
|
||||
}
|
||||
|
||||
U0 PatchJmpRel32(U32 from, U32 to) {
|
||||
*(from(U8 *)) = 0xE9;
|
||||
*((from + 1)(I32 *)) = to - from - 5;
|
||||
}
|
||||
|
||||
U0 EnableSSE() {
|
||||
asm
|
||||
{
|
||||
MOV_EAX_CR0
|
||||
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
|
||||
OR AX, 0x2 // set coprocessor monitoring CR0.MP
|
||||
MOV_CR0_EAX
|
||||
MOV_EAX_CR4
|
||||
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
|
||||
MOV_CR4_EAX
|
||||
}
|
||||
}
|
||||
|
||||
EnableSSE;
|
98
src/Home/Tracker/Lib/Pci.ZC
Executable file
98
src/Home/Tracker/Lib/Pci.ZC
Executable file
|
@ -0,0 +1,98 @@
|
|||
|
||||
#define PCI_INTH_MAX 16
|
||||
|
||||
U64 pci_int_handlers[PCI_INTH_MAX];
|
||||
|
||||
class CPCIInfo
|
||||
{
|
||||
U16 vendor_id;
|
||||
U16 device_id;
|
||||
U16 command;
|
||||
U16 status;
|
||||
U32 _class;
|
||||
U32 bar[6];
|
||||
U32 cap_pointer;
|
||||
};
|
||||
|
||||
class CPCICapability
|
||||
{
|
||||
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 PCIInfoGet(I64 i, CPCIInfo *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 PCIGetCapability(I64 i, CPCICapability *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 PCIInterruptReroute(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 PCIInterruptHandlerRegister(U64 handler)
|
||||
{
|
||||
if (!handler)
|
||||
return -1;
|
||||
I64 i = 0;
|
||||
while (pci_int_handlers[i])
|
||||
i++;
|
||||
if (i > PCI_INTH_MAX - 1)
|
||||
return -1;
|
||||
pci_int_handlers[i] = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
interrupt U0 PCIInterruptHandler()
|
||||
{
|
||||
I64 i;
|
||||
for (i = 0; i < PCI_INTH_MAX; i++)
|
||||
if (pci_int_handlers[i])
|
||||
Call(pci_int_handlers[i]);
|
||||
*(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0;
|
||||
}
|
||||
|
||||
MemSet(&pci_int_handlers, NULL, sizeof(U64) * PCI_INTH_MAX);
|
||||
// IntEntrySet(0x40, &PCIInterruptHandler, IDTET_IRQ);
|
||||
// IntEntrySet(0x41, &PCIInterruptHandler, IDTET_IRQ);
|
||||
// IntEntrySet(0x42, &PCIInterruptHandler, IDTET_IRQ);
|
||||
// IntEntrySet(0x43, &PCIInterruptHandler, IDTET_IRQ);
|
||||
//PCIInterruptReroute(0x40, 0);
|
32
src/Home/Tracker/Load.ZC
Executable file
32
src/Home/Tracker/Load.ZC
Executable file
|
@ -0,0 +1,32 @@
|
|||
#define include_noreindex #include
|
||||
|
||||
include_noreindex "Lib/Debug";
|
||||
include_noreindex "Lib/Misc";
|
||||
|
||||
include_noreindex "Lib/Pci";
|
||||
include_noreindex "Lib/AC97";
|
||||
|
||||
include_noreindex "Lib/LibC";
|
||||
include_noreindex "Lib/LibHolyC";
|
||||
include_noreindex "Lib/ELF64";
|
||||
|
||||
// load_elf("dr_mp3");
|
||||
|
||||
// include_noreindex "Lib/uPNG32";
|
||||
// include_noreindex "Player32";
|
||||
|
||||
//include_noreindex "Lib/uPNG";
|
||||
// include_noreindex "Player";
|
||||
|
||||
include_noreindex "Classes"
|
||||
include_noreindex "MIDIHandling"
|
||||
include_noreindex "WaveformGen"
|
||||
// include_noreindex "UITracker"
|
||||
include_noreindex "MusicTracker"
|
||||
|
||||
|
||||
AutoComplete(0);
|
||||
|
||||
MusicTracker;
|
||||
|
||||
//InitPlayer;
|
26
src/Home/Tracker/MIDIHandling.ZC
Normal file
26
src/Home/Tracker/MIDIHandling.ZC
Normal file
|
@ -0,0 +1,26 @@
|
|||
// precalculated, takes more memory but less CPU
|
||||
F64 midi_to_freq[128] = {
|
||||
8.1758, 8.6620, 9.1770, 9.7227, 10.3009, 10.9134, 11.5623, 12.2499,
|
||||
12.9783, 13.7500, 14.5676, 15.4339, 16.3516, 17.3239, 18.3540, 19.4454,
|
||||
20.6017, 21.8268, 23.1247, 24.4997, 25.9565, 27.5000, 29.1352, 30.8677,
|
||||
32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535, 46.2493, 48.9994,
|
||||
51.9131, 55.0000, 58.2705, 61.7354, 65.4064, 69.2957, 73.4162, 77.7817,
|
||||
82.4069, 87.3071, 92.4986, 97.9989, 103.8262, 110.0000, 116.5409, 123.4708,
|
||||
130.8128, 138.5913, 146.8324, 155.5635, 164.8138, 174.6141, 184.9972, 195.9977,
|
||||
207.6523, 220.0000, 233.0819, 246.9417, 261.6256, 277.1826, 293.6648, 311.1270,
|
||||
329.6276, 349.2282, 369.9944, 391.9954, 415.3047, 440.0000, 466.1638, 493.8833,
|
||||
523.2511, 554.3653, 587.3295, 622.2540, 659.2551, 698.4565, 739.9888, 783.9909,
|
||||
830.6094, 880.0000, 932.3275, 987.7666, 1046.5023, 1108.7305, 1174.6591, 1244.5079,
|
||||
1318.5102, 1396.9129, 1479.9777, 1567.9817, 1661.2188, 1760.0000, 1864.6550, 1975.5332,
|
||||
2093.0045, 2217.4610, 2349.3181, 2489.0159, 2637.0205, 2793.8259, 2959.9554, 3135.9635,
|
||||
3322.4376, 3520.0000, 3729.3101, 3951.0664, 4186.0090, 4434.9221, 4698.6363, 4978.0317,
|
||||
5274.0410, 5587.6517, 5919.9108, 6271.9270, 6644.8752, 7040.0000, 7458.6202, 7902.1328,
|
||||
8372.0181, 8869.8442, 9397.2726, 9956.0635, 10548.0820, 11175.3034, 11839.8215, 12543.8540
|
||||
};
|
||||
|
||||
|
||||
// slower cause uses CPU but takes less memory
|
||||
F64 MidiToFreq(I64 note) {
|
||||
// A4 (MIDI note 69) = 440 Hz, and there's a 2^(1/12) ratio between adjacent semitones.
|
||||
return 440.0 * Pow(2.0, (note - 69.0) / 12.0);
|
||||
}
|
67
src/Home/Tracker/MusicTracker.ZC
Normal file
67
src/Home/Tracker/MusicTracker.ZC
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "MIDIHandling"
|
||||
#include "WaveformGen"
|
||||
|
||||
U0 AudioPlayNote(U8 note, U8 velocity) {
|
||||
U32 buffer[44100]; // One second buffer at 44.1kHz sample rate.
|
||||
F64 freq = MidiToFreq(note);
|
||||
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
|
||||
// Play the buffer using your AC97 driver:
|
||||
AudioSFXPlay(buffer, 44100); // Assuming your AudioSFXPlay function can handle this
|
||||
}
|
||||
|
||||
U0 EnterPattern(Pattern *pattern) {
|
||||
I64 row, choice;
|
||||
NoteCell *cell;
|
||||
for (row = 0; row < TRACK_LENGTH; row++) {
|
||||
cell = &pattern->cells[row];
|
||||
Print("Enter note for row %d (0-127, 0 for none): ", row);
|
||||
// cell->note = InU8;
|
||||
// if (cell->note) {
|
||||
// Print("Enter velocity for note (1-127): ");
|
||||
// cell->velocity = InU8;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
U0 PlayPattern(Pattern *pattern) {
|
||||
I64 row;
|
||||
NoteCell *cell;
|
||||
for (row = 0; row < TRACK_LENGTH; row++) {
|
||||
cell = &pattern->cells[row];
|
||||
if (cell->note) {
|
||||
// Here, use your audio driver to play the note
|
||||
// Assume a function AudioPlayNote(note, velocity) exists
|
||||
AudioPlayNote(cell->note, cell->velocity);
|
||||
}
|
||||
Sleep(100); // Adjust for tempo
|
||||
}
|
||||
}
|
||||
|
||||
U0 MusicTracker() {
|
||||
Song song;
|
||||
// Clear(&song);
|
||||
I64 choice, sc;
|
||||
while (1) {
|
||||
Print("\nMusic Tracker:\n");
|
||||
Print("1. Enter Pattern\n");
|
||||
Print("2. Play Pattern\n");
|
||||
Print("3. Exit\n");
|
||||
Print("Choice: ");
|
||||
// choice = InU8;
|
||||
choice = KeyGet(&sc);
|
||||
|
||||
switch (choice) {
|
||||
case '1':
|
||||
EnterPattern(&song.patterns[0]); // Only one pattern for simplicity
|
||||
break;
|
||||
case '2':
|
||||
PlayPattern(&song.patterns[0]);
|
||||
break;
|
||||
case '3':
|
||||
return;
|
||||
default:
|
||||
Print("Invalid choice.\n");
|
||||
}
|
||||
}
|
||||
}
|
2
src/Home/Tracker/Run.ZC
Executable file
2
src/Home/Tracker/Run.ZC
Executable file
|
@ -0,0 +1,2 @@
|
|||
Cd(__DIR__);;
|
||||
#include "Load";
|
82
src/Home/Tracker/UITracker.ZC
Normal file
82
src/Home/Tracker/UITracker.ZC
Normal file
|
@ -0,0 +1,82 @@
|
|||
//--------------------------
|
||||
// UI Functions
|
||||
//--------------------------
|
||||
|
||||
Pattern myPattern;
|
||||
|
||||
myPattern.cells[0].note = 60; // Middle C
|
||||
myPattern.cells[0].velocity = 100;
|
||||
|
||||
myPattern.cells[1].note = 62; // D
|
||||
myPattern.cells[1].velocity = 100;
|
||||
|
||||
myPattern.cells[2].note = 64; // E
|
||||
myPattern.cells[2].velocity = 100;
|
||||
U64 InU64() {
|
||||
U8 buf[32];
|
||||
InStr(buf);
|
||||
return ToI64(buf);
|
||||
}
|
||||
|
||||
U0 DisplayMainUI() {
|
||||
// Simple function to display a main menu
|
||||
DocClear;
|
||||
Print("\nMusic Tracker UI\n");
|
||||
Print("1. Enter New Pattern\n");
|
||||
Print("2. Play Pattern\n");
|
||||
Print("3. Exit\n");
|
||||
}
|
||||
|
||||
U0 HandleUserInput(Pattern *pattern) {
|
||||
I64 choice, sc;
|
||||
Print("Enter your choice: ");
|
||||
// choice = InU64;
|
||||
|
||||
switch (KeyGet(&sc)) {
|
||||
case '1':
|
||||
EnterPattern(pattern);
|
||||
break;
|
||||
case '2':
|
||||
PlayPattern(pattern);
|
||||
break;
|
||||
case '3':
|
||||
Print("Goodbye!\n");
|
||||
return; // Exit the loop and function
|
||||
default:
|
||||
Print("Invalid choice!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 ShowError(String msg) {
|
||||
// Display error messages to the user
|
||||
Print("Error: %s\n", msg);
|
||||
}
|
||||
|
||||
U0 RenderPattern(Pattern *pattern) {
|
||||
// For simplicity, just listing the notes in the pattern
|
||||
for (I64 i = 0; i < TRACK_LENGTH; i++) {
|
||||
Print("Row %d: Note %d, Velocity %d\n", i, pattern->cells[i].note, pattern->cells[i].velocity);
|
||||
}
|
||||
}
|
||||
|
||||
U0 SettingsMenu() {
|
||||
// Display and handle the settings menu
|
||||
// ...
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
// Main UI Loop
|
||||
//--------------------------
|
||||
|
||||
U0 UITrackerMainLoop(Pattern *pattern) {
|
||||
while (1) {
|
||||
DisplayMainUI();
|
||||
HandleUserInput(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
// Entry point to run the UI
|
||||
//--------------------------
|
||||
UITrackerMainLoop(&myPattern);
|
20
src/Home/Tracker/WaveformGen.ZC
Normal file
20
src/Home/Tracker/WaveformGen.ZC
Normal file
|
@ -0,0 +1,20 @@
|
|||
U0 GenerateSineWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||
I64 i;
|
||||
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF; // Adjust the amplitude based on velocity
|
||||
F64 phase_increment = (2.0 * PI * freq) / 44100.0; // Assuming a sample rate of 44.1kHz
|
||||
|
||||
F64 phase = 0.0;
|
||||
for (i = 0; i < length; i++) {
|
||||
I16 sample_value = ToI64((Sin(phase) * amplitude)); // TODO should be ToI16
|
||||
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
|
||||
phase += phase_increment;
|
||||
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// I64 sample_rate = SAMPLE_RATE // whatever your sample rate is
|
||||
// for (I64 i = 0; i < sample_duration * sample_rate; i++) {
|
||||
// sample = sin(2.0 * PI * freq * i / sample_rate);
|
||||
// // Then send 'sample' to your audio buffer/output.
|
||||
// }
|
Loading…
Reference in a new issue