Functional sound equalization live!
#10
Hello everyone in the forum. Attached is a functional program, it is a cornerstone on a possible path to an equalizer. This one is mainly focused on deep frequencies, but you can try to influence frequencies up to 5KHz with it.
I'm not educated in this field, I don't even have basic knowledge about music mixing procedures, everything I do here is logically derived and I read something somewhere.

I built it on the principle of signal subsampling. Example. You want to mix music and boost the frequency of 100 Hz. Good. So here's how I deduced it:
The basic signal has 44100 samples per second and the maximum captured frequency in such a signal is 22050 Hz. This means that for a frequency of 100 Hz we need 200 samples. So the program creates a signal by taking sample number 1 and sample number 201, looking at how much higher or lower the level of the samples is between them and calculating the missing 200 samples between them as a gradual increase or gradual difference of the signals. This creates a signal with a frequency of 100 Hz, which respects the original audio signal at its beginning and at its end.

The equalization itself is further implemented by choosing the mix ratio between this triangular signal and the original signal. These are added up and the result is then replayed. Basically, I had it in front of me in the past when I was creating WAVSAVE, but it didn't even occur to me at the time.

Before actually trying this program, I will first warn you about 4 things.
1) I tested the program only in a 32-bit IDE
2) I do not guarantee the correctness of this procedure, although it returns a fairly decent signal at deep frequencies
3) Turn down your speakers before trying, seriously loud production this time can destroy them.
4) Place correct music file name on row 2 in source code before compiling.

Program control is described in the program:

It's fully open, so you can even listen to the triangle signal itself and change the mixing level of the original signal. An equalizer should be made in a similar way, when the individual frequency curves will be mixed together with the original curve.

If someone comes up with a better solution, let them know.

Signal mixing with keys < and >
triangle signal volume (default ist 100%) can be set with keys + and -
frequency setting with keys q,w or Q,W

This source code is for QB64 2.02, I'm starting to convert it to Phoenix 3.5.0 today, 3/22/2023, I'll add it to this thread when the conversion is complete.


Code: (Select All)
$NoPrefix
s$ = "s.mp3" 'PLECE HERE CORRECT MUSIC FILE NAME!
s = SndOpen(s$)
Dim As MEM LS, RS 'arrays with default original MP3 values
Dim As Integer L1, R1, L2, R2, NL, NR 'L1, R1 - integers contains original signal values from MEMSOUND arrays, L2, R2 - the same as L1 and R1 but shifted right by KROK value, so if is created 100 Hz signal,
'                                                                        so L2 and R2 are shifted by 441 records in MEMSOUND array to right, NL, NR - for mixing both - new and original signal to new signal
LS = MemSound(s, 1)
RS = MemSound(s, 2)


'zajistit, aby pole LS a RS bylo delitelne hodnotou KROK
Dim As Offset MaxKrok, stp, krok 'varibles for reading MEMSOUND array
Dim As _Float PropocetL, PropocetR ' variables for calculating TRIANGLE signal
krok = 220 'Default is program set to creating 100 Hz (Bass) signal


MaxKrok = LS.SIZE 'maximal steps value for MEM functions

Screen NewImage(1200, 768, 256) 'graphis screen for visualising output signal

Do Until MaxKrok Mod krok * 2 = 0 'this loop ensures that when reading the field MEMSOUND to create a new signal, the field will not overflow and Memory out of range not occur.
    MaxKrok = MaxKrok - 1
Loop
'Default settings
mix = .25 'Original signal MIX level to output signal (is not volume level)
Volume = 1 'Created Signal (Created Signal) volume level

Locate 1: Print "Original Signal:"; Int(mix * 100); "%"; " Created Signal:"; Int((1 - mix) * 100); "%"; "           "
Locate 1, 90: Print "Created Signal Volume Level:"; Int(Volume * 100); "  "
Locate 2, 1: Print "Use the < and > keys to set the ratio between the original and generated signal, Q and W for freq. change, + and - for generated signal volume level."
Do Until stp >= MaxKrok - krok * 4 'read MEMSOUND array in full range
    MemGet LS, LS.OFFSET + stp, L1 'read left original signal
    MemGet RS, RS.OFFSET + stp, R1 'read right original signal

    MemGet LS, LS.OFFSET + stp + krok * 2, L2 'read left original signal shifted to right by krok's value
    MemGet RS, RS.OFFSET + stp + krok * 2, R2 'read right original signal shifted to right by krok's value

    stp = stp + krok * 2 '* 2 - values in MEMSOUND array are INTEGERS, 2 Bytes long

    PropocetL = (L2 - L1) / OffConv(krok) 'calculation of the size of the increase or decrease of the signal to create a triangular signal [LEFT]
    PropocetR = (R2 - R1) / OffConv(krok) 'calculation of the size of the increase or decrease of the signal to create a triangular signal [RIGHT]

    PrL = PropocetL
    PrR = PropocetR
    NL = L1 'reset this value (NL) to start value before create new triangle signal for left channel
    NR = R1 'reset this value (NR) to start value before create new triangle signal for right channel

    es = 0
    Locate 1, 60: Print "Frequency curve: [Hz] "; _SndRate / krok

    Locked = 0 'for the possibility of changing the frequency during playback
    Do Until es = krok 'it only reads the slice of the memsound field in which the new signal is formed
        'keyborad program setup
        k$ = InKey$
        Select Case k$
            Case ",", "<": mix = mix + .01: Locate 1: Print "Original Signal:"; Int(mix * 100); "%"; " Created Signal:"; Int(bmix * 100); "%"; "           "
            Case ".", ">": mix = mix - .01: Locate 1: Print "Original Signal:"; Int(mix * 100); "%"; " Created Signal:"; Int(bmix * 100); "%"; "           "
            Case "+": Volume = Volume + .1
                If Volume > 2 Then Volume = 2
                Locate 1, 90: Print "Created Signal Volume Level:"; Int(Volume * 100); "  " '            Volume - is created signal volume level
            Case "-": Volume = Volume - .1
                If Volume < 0 Then Volume = 0
                Locate 1, 90: Print "Created Signal Volume Level:"; Int(Volume * 100); "  "
            Case "Q", "q"
                If Locked = 0 Then
                    Locked = 1
                    krok = krok + 10
                    If krok > 550 Then krok = 550
                    MaxKrok = LS.SIZE
                    Do Until MaxKrok Mod krok * 2 = 0
                        MaxKrok = MaxKrok - 1
                    Loop
                    Locate 1, 60: Print "Frequency curve: [Hz] "; _SndRate / krok / 2
                    Exit Do
                End If
            Case "W", "w"
                If Locked = 0 Then
                    Locked = 1
                    krok = krok - 10
                    If krok < 1 Then krok = 1
                    MaxKrok = LS.SIZE
                    Do Until MaxKrok Mod krok * 2 = 0
                        MaxKrok = MaxKrok - 1
                    Loop
                    Locate 1, 60: Print "Frequency curve: [Hz] "; _SndRate / krok / 2
                    Exit Do
                End If
        End Select


        If mix < 0 Then mix = 0
        If mix > 1 Then mix = 1
        bmix = 1 - mix

        posuvX = posuvX + 1 'variable for shift curve on the screen, just for graphic, not for own sound function
        If posuvX = Width Then posuvX = 1
        Line (posuvX, 40)-(posuvX, Height), 0, BF

        MemGet LS, LS.OFFSET + (stp - krok * 2) + es * 2, L1 'krok and es varibles must be multiplied by two, because MEMGET reads INTEGER values.
        MemGet RS, RS.OFFSET + (stp - krok * 2) + es * 2, R1



        SL = L1 * mix / 32768 + (NL / 32768 * bmix * Volume) 'the same as for R1 but for left channel.
        SR = R1 * mix / 32768 + (NR / 32768 * bmix * Volume) 'R1 is original signal, mix is R1 percentage level in new signal, NR is created signal, bmix is percentage level for NR and volume is NR volume level.

        SndRaw SL, SR

        NL = NL + PrL 'signal calculation - fall or rise - formation of a triangular waveform  [LEFT]
        NR = NR + PrR 'signal calculation - fall or rise - formation of a triangular waveform [RIGHT]
        es = es + 1


        Line (posuvX, (Height / 2 - SL * 100))-(posuvX, (Height / 2 + SL * 100)), , BF 'draw output signal to screen

        Do Until SndRawLen = 0 'wait until all music samples are playing
        Loop
    Loop
Loop


Function OffConv& (InputVal As _Offset) 'convert offset value to normal long numeric value   -  tested in 32 bit IDE only
    Dim co As Long, m As _MEM
    m = _Mem(InputVal)
    _MemGet m, m.OFFSET, co
    _MemFree m
    OffConv& = co
End Function


Reply


Messages In This Thread
Functional sound equalization live! - by Petr - 08-03-2022, 03:56 PM
RE: Functional sound equalization live! - by Jack - 08-03-2022, 04:12 PM
RE: Functional sound equalization live! - by Petr - 08-03-2022, 04:19 PM
RE: Functional sound equalization live! - by Petr - 08-03-2022, 04:23 PM
RE: Functional sound equalization live! - by Petr - 08-06-2022, 01:23 PM
RE: Functional sound equalization live! - by Pete - 08-06-2022, 03:27 PM
RE: Functional sound equalization live! - by Pete - 08-06-2022, 05:37 PM
RE: Functional sound equalization live! - by Petr - 02-18-2023, 03:38 PM
RE: Functional sound equalization live! - by Petr - 02-18-2023, 08:05 PM
RE: Functional sound equalization live! - by Petr - 02-18-2023, 09:52 PM
RE: Functional sound equalization live! - by Petr - 02-19-2023, 12:40 PM
RE: Functional sound equalization live! - by Petr - 02-19-2023, 03:39 PM
RE: Functional sound equalization live! - by Petr - 02-22-2023, 07:25 PM
RE: Functional sound equalization live! - by Petr - 03-03-2023, 11:53 PM
RE: Functional sound equalization live! - by Petr - 03-04-2023, 04:21 PM
RE: Functional sound equalization live! - by Petr - 03-24-2023, 08:35 PM



Users browsing this thread: 1 Guest(s)