Sampler fix

This commit is contained in:
y4my4my4m 2023-09-04 14:17:01 +09:00
parent db77fc64d9
commit ecdb2d01c0
3 changed files with 166 additions and 89 deletions

View file

@ -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

View file

@ -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;

View file

@ -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