mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-25 23:10:32 +00:00
Sampler fix
This commit is contained in:
parent
db77fc64d9
commit
ecdb2d01c0
3 changed files with 166 additions and 89 deletions
|
@ -12,7 +12,7 @@ class NoteCell {
|
|||
U8 effect; // Future expansion for effects
|
||||
};
|
||||
|
||||
#define TRACK_LENGTH 10 // Length of each pattern in rows
|
||||
#define TRACK_LENGTH 13 // Length of each pattern in rows
|
||||
class Pattern {
|
||||
NoteCell cells[TRACK_LENGTH];
|
||||
};
|
||||
|
@ -24,6 +24,21 @@ class Song {
|
|||
};
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
#define SAMPLE_RATE 44100
|
||||
#define PI 3.1415926535897932 // i know i can just use the pi symbol
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
U0 AudioPlayNote(U8 note, U8 velocity, U8 instrument) {
|
||||
|
||||
// ultimately, we should use AC97OutputMix to be multi channel
|
||||
|
||||
FifoI64Flush(audio.output[0]);
|
||||
FifoI64Flush(audio.output[1]);
|
||||
FifoI64Flush(audio.output[2]);
|
||||
FifoI64Flush(audio.output[3]);
|
||||
//U32 buffer[SAMPLE_RATE];
|
||||
|
||||
U32 *buffer;
|
||||
|
@ -12,12 +15,13 @@ U0 AudioPlayNote(U8 note, U8 velocity, U8 instrument) {
|
|||
|
||||
if (instrument == SAMPLE)
|
||||
{
|
||||
bufferSize = 132300;
|
||||
//bufferSize = SAMPLE_RATE * 14 * 2; // 7sec * 2 two channels * 2 for some reason?
|
||||
bufferSize = 176400; // 1sec
|
||||
buffer = MAlloc(bufferSize * sizeof(U32));
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSize = SAMPLE_RATE;
|
||||
bufferSize = 11025; // SAMPLE_RATE change duration
|
||||
buffer = MAlloc(bufferSize * sizeof(U32));
|
||||
}
|
||||
|
||||
|
@ -25,37 +29,42 @@ U0 AudioPlayNote(U8 note, U8 velocity, U8 instrument) {
|
|||
|
||||
switch(instrument) {
|
||||
case PULSE1:
|
||||
GeneratePulse1Wave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
GeneratePulse1Wave(buffer, bufferSize, freq, velocity);
|
||||
break;
|
||||
case PULSE2:
|
||||
GeneratePulse2Wave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
GeneratePulse2Wave(buffer, bufferSize, freq, velocity);
|
||||
break;
|
||||
case TRIANGLE:
|
||||
GenerateTriangleWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
GenerateTriangleWave(buffer, bufferSize, freq, velocity);
|
||||
break;
|
||||
case NOISE:
|
||||
GenerateNoiseWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
GenerateNoiseWave(buffer, bufferSize, freq, velocity);
|
||||
break;
|
||||
case SAMPLE:
|
||||
PlaySample(buffer, 132300, velocity);
|
||||
PlaySample(buffer, bufferSize, note, velocity);
|
||||
Print("Buffer first values: %d, %d, %d, %d...\n", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
break;
|
||||
default:
|
||||
GenerateSineWave(buffer, SAMPLE_RATE, freq, velocity);
|
||||
GenerateSineWave(buffer, bufferSize, 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);
|
||||
U8 *instrument_name = "DEFAULT";
|
||||
if (instrument == SAMPLE) instrument_name = "SAMPLE";
|
||||
if (instrument == PULSE1) instrument_name = "PULSE1";
|
||||
if (instrument == PULSE2) instrument_name = "PULSE2";
|
||||
if (instrument == TRIANGLE) instrument_name = "TRIANGLE";
|
||||
if (instrument == NOISE) instrument_name = "NOISE";
|
||||
"Instrument: $$LTGREEN$$ %s $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", instrument_name, note;
|
||||
|
||||
AudioSFXPlay(buffer, bufferSize);
|
||||
// silly debug print
|
||||
if (instrument == SAMPLE)
|
||||
"Instrument: $$RED$$ SAMPLE $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", note;
|
||||
if (instrument == PULSE1)
|
||||
"Instrument: $$GREEN$$ PULSE1 $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", note;
|
||||
if (instrument == PULSE2)
|
||||
"Instrument: $$CYAN$$ PULSE2 $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", note;
|
||||
if (instrument == TRIANGLE)
|
||||
"Instrument: $$YELLOW$$ TRIANGLE $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", note;
|
||||
if (instrument == NOISE)
|
||||
"Instrument: $$BROWN$$ NOISE $$DKGRAY$$|$$FG$$ Note: $$YELLOW$$%d$$FG$$\n", note;
|
||||
|
||||
Free(buffer);
|
||||
}
|
||||
|
||||
|
@ -67,8 +76,9 @@ U0 PlayPattern(Pattern *pattern) {
|
|||
if (cell->note) {
|
||||
AudioPlayNote(cell->note, cell->velocity, cell->instrument);
|
||||
}
|
||||
//if (cell->instrument == SAMPLE) Sleep(2000);
|
||||
Sleep(1000); // Adjust for tempo
|
||||
if (cell->instrument == SAMPLE) Sleep(1000); // wait for 6sec for the 7sec sample test
|
||||
//Sleep(1200); // Adjust for tempo
|
||||
Sleep(300);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,47 +103,57 @@ U0 MusicTracker() {
|
|||
Song song;
|
||||
|
||||
|
||||
song.patterns[0].cells[0].note = 60; // C3
|
||||
song.patterns[0].cells[0].note = 60;
|
||||
song.patterns[0].cells[0].velocity = 100;
|
||||
song.patterns[0].cells[0].instrument = SAMPLE;
|
||||
|
||||
song.patterns[0].cells[1].note = 60; // C3
|
||||
song.patterns[0].cells[1].note = 48; // C3
|
||||
song.patterns[0].cells[1].velocity = 100;
|
||||
song.patterns[0].cells[1].instrument = PULSE1;
|
||||
song.patterns[0].cells[1].instrument = PULSE2;
|
||||
|
||||
song.patterns[0].cells[2].note = 62; // D
|
||||
song.patterns[0].cells[2].note = 60; // C3
|
||||
song.patterns[0].cells[2].velocity = 100;
|
||||
song.patterns[0].cells[2].instrument = PULSE1;
|
||||
|
||||
song.patterns[0].cells[3].note = 64; // E
|
||||
song.patterns[0].cells[3].note = 62; // D
|
||||
song.patterns[0].cells[3].velocity = 100;
|
||||
song.patterns[0].cells[3].instrument = PULSE1;
|
||||
|
||||
song.patterns[0].cells[4].note = 60; // C
|
||||
song.patterns[0].cells[4].note = 64; // E
|
||||
song.patterns[0].cells[4].velocity = 100;
|
||||
song.patterns[0].cells[4].instrument = PULSE2;
|
||||
song.patterns[0].cells[4].instrument = SAMPLE;
|
||||
|
||||
song.patterns[0].cells[5].note = 62; // D
|
||||
song.patterns[0].cells[5].note = 65; // C
|
||||
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 = 68; // D
|
||||
song.patterns[0].cells[6].velocity = 100;
|
||||
song.patterns[0].cells[6].instrument = TRIANGLE;
|
||||
song.patterns[0].cells[6].instrument = PULSE2;
|
||||
|
||||
song.patterns[0].cells[7].note = 62; // D
|
||||
song.patterns[0].cells[7].note = 72; // C
|
||||
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 = 48; // D
|
||||
song.patterns[0].cells[8].velocity = 100;
|
||||
song.patterns[0].cells[8].instrument = TRIANGLE;
|
||||
|
||||
song.patterns[0].cells[9].note = 102;
|
||||
song.patterns[0].cells[9].note = 64; // E
|
||||
song.patterns[0].cells[9].velocity = 100;
|
||||
song.patterns[0].cells[9].instrument = NOISE;
|
||||
song.patterns[0].cells[9].instrument = TRIANGLE;
|
||||
|
||||
song.patterns[0].cells[10].note = 102;
|
||||
song.patterns[0].cells[10].velocity = 70;
|
||||
song.patterns[0].cells[10].instrument = NOISE;
|
||||
|
||||
song.patterns[0].cells[11].note = 125;
|
||||
song.patterns[0].cells[11].velocity = 35;
|
||||
song.patterns[0].cells[11].instrument = NOISE;
|
||||
|
||||
song.patterns[0].cells[12].note = 65;
|
||||
song.patterns[0].cells[12].velocity = 80;
|
||||
song.patterns[0].cells[12].instrument = NOISE;
|
||||
|
||||
// Clear(&song);
|
||||
I64 sc;
|
||||
|
|
|
@ -105,33 +105,18 @@ U0 ApplyEnvelope(U32 *buffer, I64 length) {
|
|||
// }
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
// if (gSampleData) {
|
||||
// Free(gSampleData);
|
||||
// }
|
||||
|
||||
gSampleSize = fileSize - sizeof(WAVHeader);
|
||||
|
||||
//gSampleData = MAlloc(gSampleSize);
|
||||
|
||||
|
||||
|
@ -154,17 +139,17 @@ U0 LoadSample(U8 *filename) {
|
|||
//}
|
||||
|
||||
|
||||
//U8 *fileContent = FileRead(filename, &fileSize);
|
||||
//U8 *fileContent = FileRead(filename, &gSampleSize);
|
||||
//U8 *audioDataStart = fileContent + sizeof(WAVHeader); // Move pointer after header
|
||||
//MemCopy(gSampleData, audioDataStart, gSampleSize);
|
||||
|
||||
|
||||
|
||||
// DEBUG
|
||||
//gSampleSize = sizeof(fileContent) - 36;
|
||||
//gSampleSize = fileSize - 36;
|
||||
//U8 *audioDataStart = fileContent + 36; // Move pointer after header MANUAL 36 bytes
|
||||
//MemCopy(gSampleData, audioDataStart, 36);
|
||||
// gSampleSize = fileSize - 44;
|
||||
|
||||
//U8 *audioDataStart = fileContent + 44; // Move pointer after header MANUAL 36 bytes
|
||||
//MemCopy(gSampleData, audioDataStart, gSampleSize);
|
||||
|
||||
|
||||
//Free(fileContent);
|
||||
|
@ -180,42 +165,95 @@ U0 LoadSample(U8 *filename) {
|
|||
|
||||
|
||||
}
|
||||
// // Clamping function without casting
|
||||
// I16 ClampI16(I16 value) {
|
||||
// if (value < -32768) return -32768;
|
||||
// if (value > 32767) return 32767;
|
||||
// return value;
|
||||
// }
|
||||
|
||||
U0 PlaySample(U32 *buffer, I64 duration, U8 velocity) {
|
||||
|
||||
F64 GetPlaybackRateMultiplier(U8 targetNote, U8 referenceNote) {
|
||||
I64 semitoneDifference = targetNote - referenceNote;
|
||||
return Pow(2.0, semitoneDifference / 12.0);
|
||||
}
|
||||
|
||||
U0 PlaySample(U32 *buffer, I64 duration, U8 note, U8 velocity) {
|
||||
if (!gSampleData || !gSampleSize) {
|
||||
Print("Sample not loaded.\n");
|
||||
return;
|
||||
}
|
||||
// Just as an example: copy loaded sample to buffer
|
||||
I64 samplesToCopy = Min(gSampleSize, duration); // don't overflow the buffer
|
||||
MemCopy(buffer, gSampleData, samplesToCopy);
|
||||
|
||||
// F64 multiplier = GetPlaybackRateMultiplier(note, C3_NOTE_VALUE);
|
||||
// Print("Playing with multiplier: %f\n", multiplier); // Add this print statement
|
||||
|
||||
// I64 srcIndex = 0;
|
||||
// I64 destIndex;
|
||||
// for (destIndex = 0; destIndex < duration; destIndex++) {
|
||||
// if (srcIndex < gSampleSize) {
|
||||
// buffer[destIndex] = gSampleData[srcIndex];
|
||||
// srcIndex = ToI64(srcIndex + multiplier);
|
||||
// } else {
|
||||
// buffer[destIndex] = 0; // fill the rest with silence
|
||||
// }
|
||||
// }
|
||||
// Print("Last srcIndex: %d\n", srcIndex); // Print the last value of srcIndex after the loop
|
||||
// Start after the WAV header
|
||||
|
||||
// I64 destIndex;
|
||||
// F64 srcPosition = 44.0; // Start after WAV header
|
||||
|
||||
|
||||
// for (destIndex = 0; destIndex < duration; destIndex++) {
|
||||
// I64 baseIndex = ToI64(srcPosition);
|
||||
|
||||
// if (baseIndex < gSampleSize - 8) { // Ensure there are enough samples ahead for interpolation
|
||||
// // Read the two stereo samples we're interpolating between
|
||||
// I16 leftSample1 = (gSampleData[baseIndex + 1] << 8) | gSampleData[baseIndex];
|
||||
// I16 rightSample1 = (gSampleData[baseIndex + 3] << 8) | gSampleData[baseIndex + 2];
|
||||
|
||||
// I16 leftSample2 = (gSampleData[baseIndex + 5] << 8) | gSampleData[baseIndex + 4];
|
||||
// I16 rightSample2 = (gSampleData[baseIndex + 7] << 8) | gSampleData[baseIndex + 6];
|
||||
|
||||
// F64 fraction = srcPosition - baseIndex;
|
||||
// // Linearly interpolate between the two samples for each channel
|
||||
// I16 leftMixed = ClampI16((1 - fraction) * leftSample1 + fraction * leftSample2);
|
||||
// I16 rightMixed = ClampI16((1 - fraction) * rightSample1 + fraction * rightSample2);
|
||||
|
||||
// buffer[destIndex] = (leftMixed & 0xFFFF) | ((rightMixed & 0xFFFF) << 16);
|
||||
// } else {
|
||||
// buffer[destIndex] = 0; // fill the rest with silence
|
||||
// }
|
||||
|
||||
// srcPosition += 4.0 * multiplier; // Move by one stereo sample, adjusted by the multiplier
|
||||
// }
|
||||
|
||||
I64 destIndex;
|
||||
F64 srcIndex = 44.0; // Start after WAV header
|
||||
|
||||
for (destIndex = 0; destIndex < duration; destIndex++) {
|
||||
F64 realIndex = srcIndex + destIndex * multiplier * 4;
|
||||
I64 baseIndex = ToI64(realIndex);
|
||||
F64 fraction = realIndex - baseIndex;
|
||||
|
||||
if (baseIndex < gSampleSize - 8) { // Ensure we can access two stereo samples
|
||||
U32 leftSample1 = gSampleData[baseIndex] + (gSampleData[baseIndex + 1] << 8);
|
||||
U32 rightSample1 = gSampleData[baseIndex + 2] + (gSampleData[baseIndex + 3] << 8);
|
||||
|
||||
U32 leftSample2 = gSampleData[baseIndex + 4] + (gSampleData[baseIndex + 5] << 8);
|
||||
U32 rightSample2 = gSampleData[baseIndex + 6] + (gSampleData[baseIndex + 7] << 8);
|
||||
|
||||
// Linear interpolation
|
||||
U32 leftSample = leftSample1 + ((leftSample2 - leftSample1) * fraction);
|
||||
U32 rightSample = rightSample1 + ((rightSample2 - rightSample1) * fraction);
|
||||
|
||||
buffer[destIndex] = (leftSample & 0xFFFF) | ((rightSample & 0xFFFF) << 16);
|
||||
} else {
|
||||
buffer[destIndex] = 0; // fill the rest with silence
|
||||
}
|
||||
}
|
||||
Print("Last srcIndex: %d\n", srcIndex);
|
||||
|
||||
//I64 numSamples = gSampleSize / 2;
|
||||
//I64 numStereoPairs = numSamples / 2;
|
||||
//I64 pairsToCopy = Min(numStereoPairs, duration);
|
||||
|
||||
//I64 i;
|
||||
|
||||
//for (i = 0; i < pairsToCopy; i++) {
|
||||
// I64 leftSample = (gSampleData[4*i] | (gSampleData[4*i + 1] << 8));
|
||||
// I64 rightSample = (gSampleData[4*i + 2] | (gSampleData[4*i + 3] << 8));
|
||||
// buffer[i] = (leftSample << 16) | (rightSample & 0xFFFF);
|
||||
//}
|
||||
|
||||
|
||||
// speed is almost good but right ear only...
|
||||
//I64 numSamples = gSampleSize / 2;
|
||||
//I64 samplesToCopy = Min(numSamples, duration); // don't overflow the buffer
|
||||
//I64 i;
|
||||
|
||||
//for (i=0; i < samplesToCopy; i++)
|
||||
//{
|
||||
// I64 sample = (gSampleData[2 * i] | (gSampleData[2 *i + 1] << 8));
|
||||
// buffer[i] = sample << 16;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//F64 playbackStep = 1.0; // 1.0 means original speed. <1.0 is slower, >1.0 is faster.
|
||||
//F64 playbackPointer = 0.0;
|
||||
//I64 i;
|
||||
|
@ -228,6 +266,10 @@ U0 PlaySample(U32 *buffer, I64 duration, U8 velocity) {
|
|||
// buffer[i] = 0; // or whatever value represents silence in your buffer
|
||||
// }
|
||||
//}
|
||||
|
||||
// Simply play the buffer
|
||||
//I64 samplesToCopy = Min(gSampleSize, duration); // don't overflow the buffer
|
||||
//MemCopy(buffer, gSampleData, samplesToCopy);
|
||||
}
|
||||
|
||||
// I64 sample_rate = SAMPLE_RATE // whatever your sample rate is
|
||||
|
|
Loading…
Reference in a new issue