mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-26 23:36:32 +00:00
Update
This commit is contained in:
parent
d05b7dbb7e
commit
77bcef3667
7 changed files with 250 additions and 36 deletions
20
src/Home/Tracker/Classes.ZC
Normal file → Executable file
20
src/Home/Tracker/Classes.ZC
Normal file → Executable file
|
@ -1,3 +1,10 @@
|
||||||
|
#define INSTRUMENT_NONE 0
|
||||||
|
#define PULSE1 1
|
||||||
|
#define PULSE2 2
|
||||||
|
#define TRIANGLE 3
|
||||||
|
#define NOISE 4
|
||||||
|
#define SAMPLE 5
|
||||||
|
|
||||||
class NoteCell {
|
class NoteCell {
|
||||||
U8 note; // MIDI note number
|
U8 note; // MIDI note number
|
||||||
U8 velocity; // Volume/Intensity
|
U8 velocity; // Volume/Intensity
|
||||||
|
@ -5,7 +12,7 @@ class NoteCell {
|
||||||
U8 effect; // Future expansion for effects
|
U8 effect; // Future expansion for effects
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TRACK_LENGTH 64 // Length of each pattern in rows
|
#define TRACK_LENGTH 10 // Length of each pattern in rows
|
||||||
class Pattern {
|
class Pattern {
|
||||||
NoteCell cells[TRACK_LENGTH];
|
NoteCell cells[TRACK_LENGTH];
|
||||||
};
|
};
|
||||||
|
@ -19,3 +26,14 @@ class Song {
|
||||||
|
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define PI 3.1415926535897932 // i know i can just use the pi symbol
|
#define PI 3.1415926535897932 // i know i can just use the pi symbol
|
||||||
|
|
||||||
|
// globals
|
||||||
|
U8 *gSampleData = NULL; // Global sample buffer
|
||||||
|
I64 gSampleSize = 0; // Size of the loaded sample
|
||||||
|
|
||||||
|
U0 CleanupWaveformGen() {
|
||||||
|
if (gSampleData) {
|
||||||
|
Free(gSampleData);
|
||||||
|
gSampleData = NULL; // Reset the pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,4 @@ include_noreindex "Lib/ELF64";
|
||||||
|
|
||||||
AutoComplete(0);
|
AutoComplete(0);
|
||||||
|
|
||||||
MusicTracker;
|
MusicTracker;
|
||||||
|
|
||||||
//InitPlayer;
|
|
0
src/Home/Tracker/MIDIHandling.ZC
Normal file → Executable file
0
src/Home/Tracker/MIDIHandling.ZC
Normal file → Executable file
|
@ -1,26 +1,37 @@
|
||||||
#include "MIDIHandling"
|
#include "MIDIHandling"
|
||||||
#include "WaveformGen"
|
#include "WaveformGen"
|
||||||
|
|
||||||
U0 ApplyEnvelope(U32 *buffer, I64 length) {
|
U0 AudioPlayNote(U8 note, U8 velocity, U8 instrument) {
|
||||||
I64 fadeLength = length * 0.1; // 10% fade in and fade out
|
|
||||||
I64 i;
|
|
||||||
for (i = 0; i < fadeLength; i++) {
|
|
||||||
F64 factor = ToI64(i / fadeLength);
|
|
||||||
buffer[i] = ToI64(buffer[i] * factor);
|
|
||||||
buffer[length - i - 1] = ToI64(buffer[length - i - 1] * factor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
U0 AudioPlayNote(U8 note, U8 velocity) {
|
|
||||||
U32 buffer[SAMPLE_RATE];
|
U32 buffer[SAMPLE_RATE];
|
||||||
F64 freq = MidiToFreq(note);
|
F64 freq = MidiToFreq(note);
|
||||||
|
// GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
|
|
||||||
|
switch(instrument) {
|
||||||
|
case PULSE1:
|
||||||
|
GeneratePulse1Wave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
|
break;
|
||||||
|
case PULSE2:
|
||||||
|
GeneratePulse2Wave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
|
break;
|
||||||
|
case TRIANGLE:
|
||||||
|
GenerateTriangleWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
|
break;
|
||||||
|
case NOISE:
|
||||||
|
GenerateNoiseWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
|
break;
|
||||||
|
case SAMPLE:
|
||||||
|
PlaySample(buffer, SAMPLE_RATE, velocity);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||||
ApplyEnvelope(buffer, SAMPLE_RATE); // TODO: Apply fade in and fade out
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ApplyEnvelope(buffer, SAMPLE_RATE); // TODO: Apply fade in and fade out
|
||||||
|
|
||||||
// Play the buffer using the AC97 driver:
|
// Play the buffer using the AC97 driver:
|
||||||
AudioSFXPlay(buffer, SAMPLE_RATE);
|
AudioSFXPlay(buffer, SAMPLE_RATE);
|
||||||
"$$YELLOW$$%d$$FG$$ ", note;
|
"Instrument: $$LTGREEN$$ %d $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", instrument, note;
|
||||||
}
|
}
|
||||||
|
|
||||||
U0 EnterPattern(Pattern *pattern) {
|
U0 EnterPattern(Pattern *pattern) {
|
||||||
|
@ -43,53 +54,60 @@ U0 PlayPattern(Pattern *pattern) {
|
||||||
for (row = 0; row < TRACK_LENGTH; row++) {
|
for (row = 0; row < TRACK_LENGTH; row++) {
|
||||||
cell = &pattern->cells[row];
|
cell = &pattern->cells[row];
|
||||||
if (cell->note) {
|
if (cell->note) {
|
||||||
AudioPlayNote(cell->note, cell->velocity);
|
AudioPlayNote(cell->note, cell->velocity, cell->instrument);
|
||||||
}
|
}
|
||||||
Sleep(900); // Adjust for tempo
|
Sleep(2900); // Adjust for tempo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
U0 MusicTracker() {
|
U0 MusicTracker() {
|
||||||
|
|
||||||
|
LoadSample("~/Tracker/Samples/Sample.WAV");
|
||||||
|
|
||||||
Song song;
|
Song song;
|
||||||
|
|
||||||
|
|
||||||
song.patterns[0].cells[0].note = 60; // C3
|
song.patterns[0].cells[0].note = 60; // C3
|
||||||
song.patterns[0].cells[0].velocity = 100;
|
song.patterns[0].cells[0].velocity = 100;
|
||||||
|
song.patterns[0].cells[0].instrument = SAMPLE;
|
||||||
|
|
||||||
song.patterns[0].cells[1].note = 62; // D
|
song.patterns[0].cells[1].note = 60; // C3
|
||||||
song.patterns[0].cells[1].velocity = 100;
|
song.patterns[0].cells[1].velocity = 100;
|
||||||
|
song.patterns[0].cells[1].instrument = PULSE1;
|
||||||
|
|
||||||
song.patterns[0].cells[2].note = 64; // E
|
song.patterns[0].cells[2].note = 62; // D
|
||||||
song.patterns[0].cells[2].velocity = 100;
|
song.patterns[0].cells[2].velocity = 100;
|
||||||
|
song.patterns[0].cells[2].instrument = PULSE1;
|
||||||
|
|
||||||
song.patterns[0].cells[3].note = 60; // C
|
song.patterns[0].cells[3].note = 64; // E
|
||||||
song.patterns[0].cells[3].velocity = 100;
|
song.patterns[0].cells[3].velocity = 100;
|
||||||
|
song.patterns[0].cells[3].instrument = PULSE1;
|
||||||
|
|
||||||
song.patterns[0].cells[4].note = 62; // D
|
song.patterns[0].cells[4].note = 60; // C
|
||||||
song.patterns[0].cells[4].velocity = 100;
|
song.patterns[0].cells[4].velocity = 100;
|
||||||
|
song.patterns[0].cells[4].instrument = PULSE2;
|
||||||
|
|
||||||
song.patterns[0].cells[5].note = 64; // E
|
song.patterns[0].cells[5].note = 62; // D
|
||||||
song.patterns[0].cells[5].velocity = 100;
|
song.patterns[0].cells[5].velocity = 100;
|
||||||
|
song.patterns[0].cells[5].instrument = PULSE2;
|
||||||
|
|
||||||
song.patterns[0].cells[6].note = 60; // C
|
song.patterns[0].cells[6].note = 60; // C
|
||||||
song.patterns[0].cells[6].velocity = 100;
|
song.patterns[0].cells[6].velocity = 100;
|
||||||
|
song.patterns[0].cells[6].instrument = TRIANGLE;
|
||||||
|
|
||||||
song.patterns[0].cells[7].note = 62; // D
|
song.patterns[0].cells[7].note = 62; // D
|
||||||
song.patterns[0].cells[7].velocity = 100;
|
song.patterns[0].cells[7].velocity = 100;
|
||||||
|
song.patterns[0].cells[7].instrument = TRIANGLE;
|
||||||
|
|
||||||
song.patterns[0].cells[8].note = 64; // E
|
song.patterns[0].cells[8].note = 64; // E
|
||||||
song.patterns[0].cells[8].velocity = 100;
|
song.patterns[0].cells[8].velocity = 100;
|
||||||
|
song.patterns[0].cells[8].instrument = TRIANGLE;
|
||||||
|
|
||||||
song.patterns[0].cells[9].note = 65; // F
|
song.patterns[0].cells[9].note = 102;
|
||||||
song.patterns[0].cells[9].velocity = 100;
|
song.patterns[0].cells[9].velocity = 100;
|
||||||
|
song.patterns[0].cells[9].instrument = NOISE;
|
||||||
|
|
||||||
song.patterns[0].cells[10].note = 72; // C4
|
|
||||||
song.patterns[0].cells[10].velocity = 100;
|
|
||||||
|
|
||||||
song.patterns[0].cells[11].note = 76; // E4
|
|
||||||
song.patterns[0].cells[11].velocity = 100;
|
|
||||||
|
|
||||||
song.patterns[0].cells[12].note = 36; // C1
|
|
||||||
song.patterns[0].cells[12].velocity = 100;
|
|
||||||
|
|
||||||
// Clear(&song);
|
// Clear(&song);
|
||||||
I64 sc;
|
I64 sc;
|
||||||
|
@ -116,4 +134,5 @@ U0 MusicTracker() {
|
||||||
Print("Invalid choice.\n");
|
Print("Invalid choice.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CleanupWaveformGen(); // Free the sample buffer
|
||||||
}
|
}
|
||||||
|
|
BIN
src/Home/Tracker/Samples/Sample.WAV
Executable file
BIN
src/Home/Tracker/Samples/Sample.WAV
Executable file
Binary file not shown.
0
src/Home/Tracker/UITracker.ZC
Normal file → Executable file
0
src/Home/Tracker/UITracker.ZC
Normal file → Executable file
181
src/Home/Tracker/WaveformGen.ZC
Normal file → Executable file
181
src/Home/Tracker/WaveformGen.ZC
Normal file → Executable file
|
@ -1,7 +1,7 @@
|
||||||
U0 GenerateSineWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
U0 GenerateSineWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
I64 i;
|
I64 i;
|
||||||
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF; // Adjust the amplitude based on velocity
|
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_increment = (2.0 * PI * freq) / SAMPLE_RATE; // Assuming a sample rate of 44.1kHz
|
||||||
|
|
||||||
F64 phase = 0.0;
|
F64 phase = 0.0;
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
|
@ -12,6 +12,185 @@ U0 GenerateSineWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U0 GeneratePulse1Wave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
|
I64 i;
|
||||||
|
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF;
|
||||||
|
F64 phase_increment = (2.0 * PI * freq) / SAMPLE_RATE;
|
||||||
|
F64 phase = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
I16 sample_value;
|
||||||
|
if (phase < PI) {
|
||||||
|
sample_value = ToI64(amplitude);
|
||||||
|
} else {
|
||||||
|
sample_value = -ToI64(amplitude);
|
||||||
|
}
|
||||||
|
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
|
||||||
|
phase += phase_increment;
|
||||||
|
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 GeneratePulse2Wave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
|
I64 i;
|
||||||
|
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF;
|
||||||
|
F64 phase_increment = (2.0 * PI * freq) / SAMPLE_RATE;
|
||||||
|
F64 phase = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
I16 sample_value;
|
||||||
|
if (phase < 0.5 * PI) {
|
||||||
|
sample_value = -ToI64(amplitude);
|
||||||
|
} else {
|
||||||
|
sample_value = ToI64(amplitude);
|
||||||
|
}
|
||||||
|
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
|
||||||
|
phase += phase_increment;
|
||||||
|
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 GenerateTriangleWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
|
I64 i;
|
||||||
|
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF;
|
||||||
|
F64 phase_increment = (2.0 * PI * freq) / SAMPLE_RATE;
|
||||||
|
F64 phase = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
I16 sample_value;
|
||||||
|
if (phase < PI) {
|
||||||
|
sample_value = ToI64((phase / PI) * amplitude);
|
||||||
|
} else {
|
||||||
|
sample_value = ToI64((2.0 - (phase / PI)) * amplitude);
|
||||||
|
}
|
||||||
|
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
|
||||||
|
phase += phase_increment;
|
||||||
|
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 GenerateNoiseWave(U32 *buffer, I64 length, F64 freq, U8 velocity) {
|
||||||
|
I64 i;
|
||||||
|
F64 amplitude = (ToF64(velocity) / 127.0) * 0x7FFF;
|
||||||
|
F64 phase_increment = (2.0 * PI * freq) / SAMPLE_RATE;
|
||||||
|
F64 phase = 0.0;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
I16 sample_value = ToI64((RandI64 / 0x7FFFFFFF) * amplitude);
|
||||||
|
buffer[i] = (sample_value << 16) | (sample_value & 0xFFFF);
|
||||||
|
phase += phase_increment;
|
||||||
|
if (phase >= 2.0 * PI) phase -= 2.0 * PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 ApplyEnvelope(U32 *buffer, I64 length) {
|
||||||
|
I64 i;
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
I64 sample = buffer[i];
|
||||||
|
I64 left = sample >> 16;
|
||||||
|
I64 right = sample & 0xFFFF;
|
||||||
|
left = (left * i) / length;
|
||||||
|
right = (right * (length - i)) / length;
|
||||||
|
buffer[i] = (left << 16) | (right & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// U0 ApplyEnvelope(U32 *buffer, I64 length) {
|
||||||
|
// I64 fadeLength = length * 0.1; // 10% fade in and fade out
|
||||||
|
// I64 i;
|
||||||
|
// for (i = 0; i < fadeLength; i++) {
|
||||||
|
// F64 factor = ToI64(i / fadeLength);
|
||||||
|
// buffer[i] = ToI64(buffer[i] * factor);
|
||||||
|
// buffer[length - i - 1] = ToI64(buffer[length - i - 1] * factor);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class WAVHeader {
|
||||||
|
U8 riff[4]; // RIFF string
|
||||||
|
U32 overall_size; // overall size of file in bytes
|
||||||
|
U8 wave[4]; // WAVE string
|
||||||
|
U8 fmt_chunk[4]; // fmt string with trailing null char
|
||||||
|
U32 length; // length of format data. Should be 16 for PCM
|
||||||
|
U16 format_type; // format type. 1 for PCM
|
||||||
|
U16 channels; // number of channels
|
||||||
|
U32 sample_rate; // sampling rate (blocks per second)
|
||||||
|
U32 byterate; // SampleRate * NumChannels * BitsPerSample/8
|
||||||
|
U16 block_align; // channels * bits/sample / 8
|
||||||
|
U16 bits_per_sample;// bits per sample, 8- 8bits, 16- 16 bits etc
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
U0 LoadSample(U8 *filename) {
|
||||||
|
//WAVHeader header;
|
||||||
|
I64 fileSize;
|
||||||
|
|
||||||
|
|
||||||
|
// Free any previously loaded sample
|
||||||
|
if (gSampleData) {
|
||||||
|
Free(gSampleData);
|
||||||
|
}
|
||||||
|
|
||||||
|
gSampleSize = fileSize - sizeof(WAVHeader);
|
||||||
|
//gSampleData = MAlloc(gSampleSize);
|
||||||
|
|
||||||
|
|
||||||
|
//U8 *buffer = FileRead(filename, &fileSize);
|
||||||
|
|
||||||
|
//if (buffer)
|
||||||
|
//{
|
||||||
|
// MemCopy(&header, buffer, sizeof(WAVHeader));
|
||||||
|
// Print("Got: %c %c %c %c\n", header.riff[0], header.riff[1], header.riff[2], header.riff[3]);
|
||||||
|
// Basic validation - check the RIFF and WAVE tags
|
||||||
|
// if (!StrCompare("RIFF", header.riff) || !StrCompare("WAVE", header.wave)) {
|
||||||
|
// Print("Invalid WAV file.\n");
|
||||||
|
// Free(buffer);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//} else {
|
||||||
|
// Print("Failed to read the file.\n");
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
//U8 *fileContent = FileRead(filename, &fileSize);
|
||||||
|
//U8 *audioDataStart = fileContent + sizeof(WAVHeader); // Move pointer after header
|
||||||
|
//MemCopy(gSampleData, audioDataStart, gSampleSize);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
//gSampleSize = sizeof(fileContent) - 36;
|
||||||
|
//U8 *audioDataStart = fileContent + 36; // Move pointer after header MANUAL 36 bytes
|
||||||
|
//MemCopy(gSampleData, audioDataStart, 36);
|
||||||
|
|
||||||
|
|
||||||
|
//Free(fileContent);
|
||||||
|
|
||||||
|
// test without skipping header
|
||||||
|
gSampleData = FileRead(filename, &gSampleSize);
|
||||||
|
|
||||||
|
// Print some info about the sample
|
||||||
|
//Print("Sample rate: %d\n", header.sample_rate);
|
||||||
|
//Print("Channels: %d\n", header.channels);
|
||||||
|
//Print("Bits per sample: %d\n", header.bits_per_sample);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 PlaySample(U32 *buffer, I64 duration, U8 velocity) {
|
||||||
|
if (!gSampleData || !gSampleSize) {
|
||||||
|
Print("Sample not loaded.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Just as an example: copy loaded sample to buffer
|
||||||
|
// This step will depend on how you are processing and playing the audio
|
||||||
|
I64 samplesToCopy = Min(gSampleSize, duration); // don't overflow the buffer
|
||||||
|
MemCopy(buffer, gSampleData, samplesToCopy);
|
||||||
|
|
||||||
|
// Here you'd typically send the buffer to your audio playing routine
|
||||||
|
}
|
||||||
|
|
||||||
// I64 sample_rate = SAMPLE_RATE // whatever your sample rate is
|
// I64 sample_rate = SAMPLE_RATE // whatever your sample rate is
|
||||||
// for (I64 i = 0; i < sample_duration * sample_rate; i++) {
|
// for (I64 i = 0; i < sample_duration * sample_rate; i++) {
|
||||||
|
|
Loading…
Reference in a new issue