Takes a music WAV file that can be listenned on headphones from a sound inside your head into a 3D stage in a 3D speakers sound in the same headphnes.
This very simple program will process a music wav file that is normally more or less inside your head, depending if you are leastening with planar magnetics or dynamic headphones, and puts the sound in a 3D stage in front of you. You can tune the parameters for your head size and for you headphones, I tryed with HIFIman Edition XS and with Beyerdynamics DT990 Pro. And both of them, at least to my ears become better with this effect, and much less tiaring when used for a long time.
holographic_effect : f64 = 0.5 // -1.0 to 1.0 ( Depth / Head physics )
soundstage_effect : f64 = 0.4 // -1.0 to 1.0 ( Width / Mid-Side ratio )
crossfeed_level : f64 = 0.4
Audio files store data in whole numbers ( integers ), but doing complex math on integers ruins the sound quality due to rounding errors.
The bytes_to_f64 and f64_to_bytes functions are the gatekeepers. They read the raw 16, 24, or 32-bit integer chunks and convert them into 64-bit floating-point numbers ( f64 ) ranging from -1.0 to +1.0.
The 24-bit Magic: 24-bit audio is tricky because computers process data in chunks of 8, 16, or 32. The code manually stitches three 8-bit bytes together and uses a bitwise check (if val & 0x800000 != 0) to determine if the audio wave is in the negative phase, perfectly preserving the studio master quality.
Before doing any crossfeed, the program alters the perceived width of the room using the soundstage_effect variable.
It splits the Left and Right channels into "Mid" ( what is identical in both ears, like the lead vocals ) and "Side" ( what is different, like wide guitars or room reverb ).
Formulas for Mid/Side:
Mid = ( Sample_L + Sample_R ) / 2.0
Side = ( Sample_L - Sample_R ) / 2.0
Next, it applies your custom gains. Because your soundstage_effect is 0.3, it boosts the Side volume by 12% ( 0.3 * 0.4 ) and dips the Mid volume by 3% ( 0.3 * 0.1 ).
Finally, it reconstructs the Left and Right channels:
Stage_L = ( Mid * Mid_Gain ) + ( Side * Side_Gain )
Stage_R = ( Mid * Mid_Gain ) - ( Side * Side_Gain )
To make the sound "holographic," the brain needs timing cues. If a sound comes from the left, it hits your left ear first, and your right ear a fraction of a millisecond later.
The DelayLine struct creates a "Ring Buffer." It acts like a bucket line:
-
It reads the oldest audio sample out of the bucket.
-
It puts the brand-new audio sample into that exact spot.
-
It moves to the next bucket.
-
Based on the holographic_effect of 0.5, the calculated delay is exactly 0.000325 seconds (325 microseconds), which simulates the exact time it takes for sound to wrap around an average human head.
The head is a physical obstacle. It blocks high frequencies ( like cymbals ) from wrapping around to the opposite ear, but lets low frequencies ( like bass guitars ) pass through easily.
The Filter struct uses a "1-Pole Infinite Impulse Response ( IIR )" formula to muffle the delayed audio. Based on your 0.5 holographic setting, the cutoff frequency is set to 550 Hz.
Formula for the Filter Coefficients:
b1 = exp( -2.0 * PI * cutoff_freq / sample_rate )
a0 = 1.0 - b1
Formula for Filtering the Audio:
Output = ( Input * a0 ) + ( Previous_Output * b1 )
The main loop ties everything together frame by frame.
It takes the widened Stage_L, runs it through the Delay, runs that delayed signal through the Filter, and creates Cross_L. It does the same for the right side to create Cross_R.
Finally, it mixes the opposite channel's muffled, delayed signal into the main ear, scales it by the crossfeed_level (0.4), and lowers the master volume ( 0.85 ) so the added sound doesn't cause digital clipping.
Formula for the Final Mix:
Out_L = ( Stage_L + ( Cross_R * Crossfeed_Level ) ) * Master_Gain
Out_R = ( Stage_R + ( Cross_L * Crossfeed_Level ) ) * Master_Gain
make clean
make
./headphones_to_3d_speakers.exe <input_file.wav> <output_file.wav>
MIT Open Source License
Best regards,
Joao Carvalho