B4J Question Sound generator: 2 channels

peacemaker

Expert
Licensed User
Longtime User
Hi, All

Any suggestion how to make a sound generator of 2 channels: one sine wave to the left channel, another sine wave to second channel ?
If non-crossplatform solution, then for Windows.
 

peacemaker

Expert
Licensed User
Longtime User
Phase shift:
Here also no anti-phase addition of signals of the same frequency / shape ...
I hope to hear lowering the sound, if to generate them in anti-phase...

But generation seems, OK:
1669890212366.png
 
Last edited:
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Here also no anti-phase addition of signals of the same frequency / shape ...
I hope to hear lowering the sound, if to generate them in anti-phase...

Can you elaborate the problem? If two reverse-phased waves are added/mixed together in one channel they will be zero/silence.
 
Last edited:
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Indeed, it needs to blend in one channel. It will be done during physics experiments, connecting both signals to a some test summ schema.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
New trouble - why volume level of the lowest freq < 200 Hz is going to zero in this code ?

Mono-generator (with pre-set wave shape) can generate noticeable 20...50 Hz via the same my audio-subsystem.
If to make amplification during the data calculation - the distorted 20...50 Hz sound is rather loud.

p.s. seems, the generation of the clean sine is just filtered by the audio-amplifier at point around 150 Hz, of my system.
And distorted wave is ... more digitized, and loud.

But mono-generator was better :)
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Righto, I'm a bit late to this afterparty, but I've got it working so I may as well post it, maybe it might spark some ideas.

Plus I've got it working with three - count 'em, three - sine waves, and they work from wavetables that could just as easily do square waves, triangular waves, or even include integral overtones.

Phase is independently adjustable for all generators x channels, in case your physics stuff involves simulating beamforming.

Ditto audio level - if you want the first sine wave coming out of the left speaker, the second out of the right speaker, and the third split 40:60 left:right, then mate I have headed you off at the pass and then some. 🤣

Globals:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    
    Dim NumGenerators As Int = 3    'in for a penny, in for a pound
    Dim NumChannels As Int = 2    'left = 0, right = 1
    
    Dim Frequency(NumGenerators) As Float    'Hz
    Dim Level(NumGenerators, NumChannels) As Int    '0 to 100%
    Dim Phase(NumGenerators, NumChannels) As Float    '0 to 360 degrees
    
    Dim PhaseAccumulator(NumGenerators) As Int    'binary fixed-point 16.16
    Dim PhaseIncrement(NumGenerators) As Int    'binary fixed-point 16.16
    Dim PhaseShift(NumGenerators, NumChannels) As Int    'binary fixed-point 16.16
    
    Dim WaveTableSize As Int = 256    'power of 2
    Dim WaveTableIndexMask As Int = WaveTableSize - 1    '0b11111111
    
    Dim WaveTables(NumGenerators) As Object    'pretty sure that Android audio uses signed 16-bit samples
    
    Dim SampleRate As Int = 44100    '30 frames/second x 490 lines/frame x 3 samples/line

    Dim Streamer As AudioStreamer
    
End Sub

Prepare (just once) a single-cycle wavetable:
Sub MakeSineWaveTable(NumSamples As Int) As Short()

    Dim S(NumSamples) As Short

    For I = 0 To NumSamples - 1
        Dim Angle As Float = I * 2 * cPI / NumSamples
        Dim Sample As Float = Sin(Angle) * 32768
        If Sample < -32768 Then
            Sample = -32768
        else if Sample > 32767 Then
            Sample = 32767
        End If
        
        S(I) = Sample
    Next
    
    Return S
    
End Sub

Translate 'user' settings to internal formats for faster sample generation:
Sub UpdateGeneratorParameters(Generator As Int)
    
    PhaseIncrement(Generator) = FrequencyToPhaseIncrement(Frequency(Generator))
    For C = 0 To NumChannels - 1
        PhaseShift(Generator, C) = PhaseToPhaseShift(Phase(Generator, C))
    Next
    
End Sub


Sub FrequencyToPhaseIncrement(Hertz As Float) As Int

    Return Hertz / SampleRate * WaveTableSize * 0x10000 + 0.5   'amount to increment phase accumulator by each sample time
    
End Sub


Sub PhaseToPhaseShift(Degrees As Float) As Int

    Return Degrees / 360 * WaveTableSize * 0x10000 + 0.5

End Sub

Generate samples ready(ish) to send to audio output device:
Sub GenerateSamples(NumSamples As Int) As Short()

    Dim S(NumChannels * NumSamples) As Short
    
    Dim SP As Int = 0
    
    Dim TotalChannelSample(NumChannels) As Int
    For I = 1 To NumSamples
        For C = 0 To NumChannels - 1
            TotalChannelSample(C) = 0
        Next
        
        For G = 0 To NumGenerators - 1
            Dim WaveTable() As Short = WaveTables(G)    'cast from object wtf
            
            PhaseAccumulator(G) = Bit.And(PhaseAccumulator(G) + PhaseIncrement(G), 0x3FFFFFFF)    'clear high two bits to avoid Int overflow
            
            For C = 0 To NumChannels - 1
                Dim WaveTableIndex As Int = Bit.ShiftRight(PhaseAccumulator(G) + PhaseShift(G, C), 16)
                Dim WaveSample As Int = WaveTable(Bit.And(WaveTableIndex, WaveTableIndexMask))
                Dim ChannelSample As Int = (WaveSample * Level(G, C) + 50) / 100
                TotalChannelSample(C) = TotalChannelSample(C) + ChannelSample
            Next
        Next
        
        For C = 0 To NumChannels - 1
            Dim Temp As Int = TotalChannelSample(C)
            If Temp < -32768 Then
                Temp = -32768
            else if Temp > 32767 Then
                Temp = 32767
            End If
            
            S(SP) = Temp
            SP = SP + 1    'interleaved channel eg 5.1 = 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5
        Next
    Next
    
    Return S
    
End Sub

and to finally get the show on the road:
Sub Activity_Create(FirstTime As Boolean)

    WaveTables(0) = MakeSineWaveTable(WaveTableSize)    'could do in loop
    WaveTables(1) = MakeSineWaveTable(WaveTableSize)    'but maybe one day might have
    WaveTables(2) = MakeSineWaveTable(WaveTableSize)    'different waveform for each channel

    'default Level and Phase parameters aka Captain Lazy Strikes Again
    For G = 0 To NumGenerators - 1
        For C = 0 To NumChannels - 1
            Level(G, C) = 0
            Phase(G, C) = 0
        Next
    Next

    Frequency(0) = 440
    Level(0, 0) = 30
    
    Frequency(1) = 439
    Level(1, 1) = 20
    
    Frequency(2) = 438
    Level(2, 0) = 10
    
    For G = 0 To NumGenerators - 1   
        UpdateGeneratorParameters(G)
    Next

    Streamer.Initialize("streamer", 44100, False, 16, Streamer.VOLUME_MUSIC)
    
    Streamer.StartPlaying
    
    Dim bc As ByteConverter
    bc.LittleEndian = True
    
    For TenthOfSecond = 1 To 100    '10 seconds
        Dim S() As Short = GenerateSamples(SampleRate / 10)
        Log(Streamer.Write(bc.ShortsToBytes(S)))
    Next
    
    Streamer.Write(Null) 'when this "message" will be processed, the player will stop.
    
End Sub
 
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
New trouble - why volume level of the lowest freq < 200 Hz is going to zero in this code ?

Mono-generator (with pre-set wave shape) can generate noticeable 20...50 Hz via the same my audio-subsystem.
If to make amplification during the data calculation - the distorted 20...50 Hz sound is rather loud.

p.s. seems, the generation of the clean sine is just filtered by the audio-amplifier at point around 150 Hz, of my system.
And distorted wave is ... more digitized, and loud.

The sine wave with freq < 200Hz is there, just most of our lovely forum senior members can't hear that because of our ears are getting old, not sensitive to lower frequency anymore - sad but true. :(

The mono-generator generates distorted sine wave, not even sine wave, more like a saw and square wave, so there are many high frequency components in this wave accompanying the dominant main freq, those high freqs make it sound lound.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
ears are getting old
Agreed, but i have just tested with my daughter (22 yr old):
1) hi-freq she can hear the pure sine sound up to 15.700 Hz, me upto 10.000 Hz max.
2) But low freq - the same situation, we cannot hear < 100 Hz of pure sine from this notebook.

So, i think, it's filtered by the audio-amplifier, not by old ear :)
 
Last edited:
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
it's filtered by the audio-amplifier

As we people can hear frequency from 20 to 20000Hz, most audio systems are designed for this range, there should be no filter intended putting there to make sound bad. However, the system can't be ideal and alway has its own certain non-linear frequency response, so I agree there are filters there like a drive unit in speakers, if it is too big then it is good for low freq, but bad for high freq as high freq doesn't have enough time to vibrate it fully as it is too big so it works like low pass filter.

Now I want to test what freq range I can hear... it is true that more older more loss on high freq than low freq. Also agree that normal people can't hear low freq well...
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
There is probably no filtering in the notebook electronics, but small speakers are unlikely to be able to reproduce low sounds accurately, if at all.

I just tested on my 5" studio monitors and can hear a note down to 39Hz and a click after that and up to 12700Hz. I would probably hear a bit wider range on larger speakers or higher volume.
 
Last edited:
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
Just tried on my laptop, with my ear paste to the speaker of the laptop, I can hear 14000Hz, for 50Hz the speaker generates some sound I can hear but I am not even sure it is the true sound of 50Hz, sounds like some "ta ta ta" noise. It seems the key factor for a good audio system is the speaker as modern analog/digital electronics are already quite good.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Upvote 0

Magma

Expert
Licensed User
Longtime User
You are right that seems the audio system especially the speaker has more impact than getting old. Literature shows getting old is more related to high freq loss.
supergran 1.jpg

I don't agree... with you... supergran was hearing very good ! (what i ve remembered)
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
I can tell like other old guys here (hey I am not so old as others :cool:)...

It is impossible not recognize her.... it was an 80's TV series from BBC... played at the half planet.... may be you were at the other half... :)
she had bionic hearing - ears... what ever...
 
Upvote 0
Top