diff --git a/jerdehl.c b/jerdehl.c index 7ea0c62..376d6b1 100644 --- a/jerdehl.c +++ b/jerdehl.c @@ -5,19 +5,17 @@ #include #define SINE_TABLE_SIZE 2048 -#define ZERO_FIVE 0.5 -#define ZERO_THREE 0.3 #define UINT32_MAX_HALF (UINT32_MAX / 2) #define CHORD_NOTES 3 -#define CHORD_TYPES 21 +#define CHORD_TYPES 7 -float sinetab[SINE_TABLE_SIZE]; +double sinetab[SINE_TABLE_SIZE]; typedef struct oscillator { uint32_t phasor; uint32_t step; - float value; + double value; } osc_t; typedef struct @@ -26,54 +24,70 @@ typedef struct int noteDuration; } PianoOscillator; -// Frequencies for chords in the key of C (C, Dm, Em, F, G, Am) +typedef struct noise_oscillator +{ + uint32_t seed; + double value; +} noise_osc_t; + +double generate_noise(noise_osc_t *n) +{ + // A simple pseudo-random noise generator + n->seed = (n->seed * 1103515245 + 12345) & 0x7fffffff; + return (double)n->seed / 0x40000000 - 1.0; // Normalize to range -1.0 to 1.0 +} + +void init_noise_osc(noise_osc_t *n, uint32_t seed) +{ + n->seed = seed; +} + + +double update_crackle(noise_osc_t *n) +{ + // Generate the base noise + double noise = generate_noise(n); + // Apply random volume modulation to simulate the crackling effect + double volume = 0 + ((double)rand() / RAND_MAX) * 0.5; // Random volume between 0.2 and 1.0 + // Occasionally spike the volume to simulate louder crackles + if ((rand() % 100) < 40) // 10% chance for a louder crackle + { + volume += 0.5; // Increase volume for a louder crackle + } + // Clamp the volume to avoid clipping + volume = (volume > 1.0) ? 1.0 : volume; + // Apply the volume to the noise + noise *= volume; + // Clamp the noise to avoid clipping + return noise; +} + + + float chordFrequencies[CHORD_TYPES][CHORD_NOTES] = { - {65.41, 77.78, 98.00}, // Cm (C, Eb, G) - {87.31, 98.00, 116.54}, // Fm7 (F, G, Bb) - {73.42, 87.31, 110.00}, // Ddim (D, F, A) - {61.74, 77.78, 92.50}, // G7 (G, B, F) - {58.27, 73.42, 87.31}, // BbMaj (Bb, D, F) - {65.41, 82.41, 103.83}, // Cm/Ab (Ab, C, Eb) - {73.42, 92.50, 116.54}, // D7 (D, F#, A, C) - {65.41, 77.78, 98.00}, // Cm (C, Eb, G) repeat - {58.27, 73.42, 87.31}, // BbMaj (Bb, D, F) repeat - {61.74, 77.78, 92.50}, // G7 (G, B, F) repeat - {77.78, 98.00, 123.47}, // EbMaj (Eb, G, Bb) - {82.41, 103.83, 130.81}, // AbMaj (Ab, C, Eb) - {87.31, 110.00, 130.81}, // FMaj7 (F, A, C, E) - {98.00, 123.47, 146.83}, // GMaj (G, B, D) - {103.83, 130.81, 155.56}, // AbMaj7 (Ab, C, Eb, G) - {110.00, 130.81, 164.81}, // AMaj7 (A, C#, E, G#) - {116.54, 146.83, 174.61}, // BbMaj (Bb, D, F) - {123.47, 155.56, 185.00}, // EbMaj7 (Eb, G, Bb, D) - {130.81, 164.81, 195.00}, // FMaj (F, A, C) - {146.83, 174.61, 220.00}, // GMaj7 (G, B, D, F#) - {65.41, 77.78, 98.00} // Cm (C, Eb, G) + {65.41, 77.78, 98.00}, // Cm (C, Eb, G) + {73.42, 87.31, 97.99}, // Ddim (D, F, Ab) + {82.41, 97.99, 123.47}, // Eb (Eb, G, Bb) + {87.31, 103.83, 130.81},// Fm (F, Ab, C) + {97.99, 116.54, 146.83},// Gm (G, Bb, D) + {103.83, 123.47, 155.56},// Ab (Ab, C, Eb) + {116.54, 130.81, 155.56},// Bb (Bb, D, F) +}; +float higherChordFrequencies[CHORD_TYPES][CHORD_NOTES] = { + {130.81, 155.56, 196.00}, // Cm (C4, Eb4, G4) + {146.83, 174.61, 195.99}, // Ddim (D4, F4, Ab4) + {164.81, 195.99, 246.94}, // Eb (Eb4, G4, Bb4) + {174.61, 207.65, 261.63}, // Fm (F4, Ab4, C5) + {195.99, 233.08, 293.66}, // Gm (G4, Bb4, D5) + {207.65, 246.94, 311.13}, // Ab (Ab4, C5, Eb5) + {233.08, 261.63, 311.13}, // Bb (Bb4, D5, F5) }; -float higherChordFrequencies[CHORD_TYPES][CHORD_NOTES] = { - {130.82 * 2, 155.56 * 2, 196.00 * 2}, // Cm (C6, Eb6, G6) - {174.62 * 2, 196.00 * 2, 233.08 * 2}, // Fm7 (F6, G6, Bb6) - {146.84 * 2, 174.62 * 2, 220.00 * 2}, // Ddim (D6, F6, A6) - {123.48 * 2, 155.56 * 2, 185.00 * 2}, // G7 (G6, B6, F6) - {116.54 * 2, 146.84 * 2, 174.62 * 2}, // BbMaj (Bb6, D6, F6) - {130.82 * 2, 164.82 * 2, 207.66 * 2}, // Cm/Ab (Ab6, C6, Eb6) - {146.84 * 2, 185.00 * 2, 233.08 * 2}, // D7 (D6, F#6, A6, C6) - {130.82 * 2, 155.56 * 2, 196.00 * 2}, // Cm (C6, Eb6, G6) repeat - {116.54 * 2, 146.84 * 2, 174.62 * 2}, // BbMaj (Bb6, D6, F6) repeat - {123.48 * 2, 155.56 * 2, 185.00 * 2}, // G7 (G6, B6, F6) repeat - {155.56 * 2, 196.00 * 2, 246.94 * 2}, // EbMaj (Eb6, G6, Bb6) - {164.82 * 2, 207.66 * 2, 261.62 * 2}, // AbMaj (Ab6, C6, Eb6) - {174.62 * 2, 220.00 * 2, 261.62 * 2}, // FMaj7 (F6, A6, C6, E6) - {196.00 * 2, 246.94 * 2, 293.66 * 2}, // GMaj (G6, B6, D6) - {207.66 * 2, 261.62 * 2, 311.12 * 2}, // AbMaj7 (Ab6, C6, Eb6, G6) - {220.00 * 2, 261.62 * 2, 329.62 * 2}, // AMaj7 (A6, C#6, E6, G#6) - {233.08 * 2, 293.66 * 2, 349.22 * 2}, // BbMaj (Bb6, D6, F6) - {246.94 * 2, 311.12 * 2, 369.99 * 2}, // EbMaj7 (Eb6, G6, Bb6, D6) - {261.62 * 2, 329.62 * 2, 391.99 * 2}, // FMaj (F6, A6, C6) - {293.66 * 2, 349.22 * 2, 440.00 * 2}, // GMaj7 (G6, B6, D6, F#6) - {130.82 * 2, 155.56 * 2, 196.00 * 2} // Cm (C6, Eb6, G6) -}; +void set_osc_freq(osc_t *o, float f) +{ + o->step = (uint32_t)((f / 16000.0) * UINT32_MAX); + o->phasor = 0; // Reset the phasor to start at the beginning of the sine wave +} void update_osc(osc_t *o) { @@ -83,79 +97,37 @@ void update_osc(osc_t *o) o->value = sinetab[index]; } -void set_osc_freq(osc_t *o, float f) -{ - o->step = (uint32_t)((f / 16000.0) * UINT32_MAX); - o->phasor = 0; // Reset the phasor to start at the beginning of the sine wave -} - -void update_piano_osc(PianoOscillator *p) -{ - if (p->noteDuration > 0) - { +void update_piano_osc(PianoOscillator *p, float chordFrequencies[CHORD_TYPES][CHORD_NOTES], int notePlayChance) { + if (p->noteDuration > 0) { // Continue playing the current chord - p->noteDuration--; // Decrement the note duration - } - else - { - // Time to play a new chord - int chordIndex = rand() % CHORD_TYPES; - for (int i = 0; i < CHORD_NOTES; ++i) - { - // Assign a new frequency to each oscillator in the chord - set_osc_freq(&p->noteOsc[i], chordFrequencies[chordIndex][i]); + double fadeOutFactor = 1.0; + int twoThirdsDuration = (2 * p->noteDuration / 3); + if (p->noteDuration <= twoThirdsDuration) { + // Calculate fade-out factor + fadeOutFactor = (double)p->noteDuration / twoThirdsDuration; + } + // Update the value for each oscillator in the chord with fade-out + for (int i = 0; i < CHORD_NOTES; ++i) { + update_osc(&p->noteOsc[i]); + p->noteOsc[i].value *= fadeOutFactor; // Apply fade-out factor } - p->noteDuration = (rand() % 5 + 1) * 16000; // Set a new random note duration - } - - // Update the value for each oscillator in the chord - for (int i = 0; i < CHORD_NOTES; ++i) - { - update_osc(&p->noteOsc[i]); - } -} - -void update_high_piano_osc(PianoOscillator *p) -{ - if (p->noteDuration > 0) - { - // Continue playing the current chord or silence p->noteDuration--; // Decrement the note duration - } - else - { + } else { // Random chance to play a new chord or not play anything (silence) - if (rand() % 10 == 0) - { // 50% chance to start a new chord, adjust as needed + if (rand() % notePlayChance == 0) { int chordIndex = rand() % CHORD_TYPES; - for (int i = 0; i < CHORD_NOTES; ++i) - { - // Assign a new frequency to each oscillator in the chord - set_osc_freq(&p->noteOsc[i], higherChordFrequencies[chordIndex][i]); + for (int i = 0; i < CHORD_NOTES; ++i) { + set_osc_freq(&p->noteOsc[i], chordFrequencies[chordIndex][i]); } - } - else - { + p->noteDuration = (rand() % 10 + 1) * 16000; // Set a new random note duration + } else { // Set all oscillator values to zero to represent silence - for (int i = 0; i < CHORD_NOTES; ++i) - { + for (int i = 0; i < CHORD_NOTES; ++i) { p->noteOsc[i].value = 0.0f; } } - // Set a new random note duration - p->noteDuration = (rand() % 5 + 1) * 16000; // E.g., between 1 and 5 seconds - } - - // Update the value for each oscillator in the chord - if (p->noteDuration > 0) - { // Only update oscillators if not in silence - for (int i = 0; i < CHORD_NOTES; ++i) - { - update_osc(&p->noteOsc[i]); - } } } - int main() { FILE *fp; @@ -181,38 +153,48 @@ int main() // Initialize the first chord and duration for piano and high piano int chordIndex = rand() % CHORD_TYPES; - pianoOsc.noteDuration = (rand() % 100 + 1) * 16000; // Start with a random duration - highPianoOsc.noteDuration = (rand() % 5 + 1) * 16000; // Start with a random duration + update_piano_osc(&pianoOsc, chordFrequencies, 10); // Start with a random duration + update_piano_osc(&highPianoOsc, higherChordFrequencies, 8); // Start with a random duration + // Set the frequencies for the first chord for (int i = 0; i < CHORD_NOTES; ++i) { set_osc_freq(&pianoOsc.noteOsc[i], chordFrequencies[chordIndex][i]); set_osc_freq(&highPianoOsc.noteOsc[i], higherChordFrequencies[chordIndex][i]); } + noise_osc_t fireCrackleOsc; + init_noise_osc(&fireCrackleOsc, time(NULL)); + while (1) { out = 0.0f; // Reset output each iteration // Update the piano and high piano oscillators - update_piano_osc(&pianoOsc); - update_high_piano_osc(&highPianoOsc); + // Update the piano oscillator + update_piano_osc(&pianoOsc, chordFrequencies, 10); // 10 for a 1 in 10 chance of silence + // Update the high piano oscillator + update_piano_osc(&highPianoOsc, higherChordFrequencies, 2); // 2 for a 1 in 2 chance of silence // Mix the outputs from all oscillators for (int i = 0; i < CHORD_NOTES; ++i) { - out += pianoOsc.noteOsc[i].value + highPianoOsc.noteOsc[i].value; + out += pianoOsc.noteOsc[i].value + (highPianoOsc.noteOsc[i].value * -1.0f); } - out /= CHORD_NOTES; // Correctly average the mixed notes + out /= (2 * CHORD_NOTES); // Correctly average the mixed notes, considering both piano and high piano + + // Fire crackling noise + double crackle = update_crackle(&fireCrackleOsc); + out += crackle * 0.1f; // Increase the gain to make the signal louder - float gain = 0.2f; // Adjust the gain factor as needed + float gain = 0.5f; // Adjust the gain factor as needed out *= gain; // Ensure the signal does not exceed the maximum range if (out > 1.0f) out = 1.0f; if (out < -1.0f) - out = 0.8f; + out = -1.0f; // Scale to 16-bit output value out16 = (uint16_t)((UINT16_MAX / 2) * (0.5 + 0.5 * out)); @@ -221,6 +203,6 @@ int main() fwrite(&out16, sizeof(out16), 1, fp); fwrite(&out16, sizeof(out16), 1, fp); } - + fclose(fp); return 0; } \ No newline at end of file