mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-25 23:10:32 +00:00
Update
This commit is contained in:
parent
d05b7dbb7e
commit
77bcef3667
7 changed files with 250 additions and 36 deletions
22
src/Home/Tracker/Classes.ZC
Normal file → Executable file
22
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 {
|
||||
U8 note; // MIDI note number
|
||||
U8 velocity; // Volume/Intensity
|
||||
|
@ -5,7 +12,7 @@ class NoteCell {
|
|||
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 {
|
||||
NoteCell cells[TRACK_LENGTH];
|
||||
};
|
||||
|
@ -18,4 +25,15 @@ class Song {
|
|||
|
||||
|
||||
#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);
|
||||
|
||||
MusicTracker;
|
||||
|
||||
//InitPlayer;
|
||||
MusicTracker;
|
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 "WaveformGen"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U0 AudioPlayNote(U8 note, U8 velocity) {
|
||||
U0 AudioPlayNote(U8 note, U8 velocity, U8 instrument) {
|
||||
U32 buffer[SAMPLE_RATE];
|
||||
F64 freq = MidiToFreq(note);
|
||||
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
ApplyEnvelope(buffer, SAMPLE_RATE); // TODO: Apply fade in and fade out
|
||||
// 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);
|
||||
break;
|
||||
}
|
||||
|
||||
//ApplyEnvelope(buffer, SAMPLE_RATE); // TODO: Apply fade in and fade out
|
||||
|
||||
// Play the buffer using the AC97 driver:
|
||||
AudioSFXPlay(buffer, SAMPLE_RATE);
|
||||
"$$YELLOW$$%d$$FG$$ ", note;
|
||||
"Instrument: $$LTGREEN$$ %d $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", instrument, note;
|
||||
}
|
||||
|
||||
U0 EnterPattern(Pattern *pattern) {
|
||||
|
@ -43,53 +54,60 @@ U0 PlayPattern(Pattern *pattern) {
|
|||
for (row = 0; row < TRACK_LENGTH; row++) {
|
||||
cell = &pattern->cells[row];
|
||||
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() {
|
||||
|
||||
LoadSample("~/Tracker/Samples/Sample.WAV");
|
||||
|
||||
Song song;
|
||||
|
||||
|
||||
song.patterns[0].cells[0].note = 60; // C3
|
||||
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].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].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].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].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].instrument = PULSE2;
|
||||
|
||||
song.patterns[0].cells[6].note = 60; // C
|
||||
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].velocity = 100;
|
||||
song.patterns[0].cells[7].instrument = TRIANGLE;
|
||||
|
||||
song.patterns[0].cells[8].note = 64; // E
|
||||
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].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);
|
||||
I64 sc;
|
||||
|
@ -116,4 +134,5 @@ U0 MusicTracker() {
|
|||
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) {
|
||||
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_increment = (2.0 * PI * freq) / SAMPLE_RATE; // Assuming a sample rate of 44.1kHz
|
||||
|
||||
F64 phase = 0.0;
|
||||
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
|
||||
// for (I64 i = 0; i < sample_duration * sample_rate; i++) {
|
||||
|
|
Loading…
Reference in a new issue