Android Question Best way to convert float to high byte low byte

Michael Gasperi

Member
Licensed User
Longtime User
Lets say I'm generating some tones by streaming audio out. The buffer for this is arranged as high byte then low byte for a 16 bit value. What would be the best way to convert a double that ranged from -1 to 1 to produce a full scale audio output?
 

stevel05

Expert
Licensed User
Longtime User
Out of curiosity, where are you getting the double that represents PCM samples?
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Where does the double come from?, what does it's values represent?
 
Upvote 0

Michael Gasperi

Member
Licensed User
Longtime User
They are the just signal values over time. For a pure tone they would be generated with the sin function. I figure +1 to -1 seems like a reasonable range.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
To produce an audio file from those, you will need to convert them to numbers between 0 and 65535 (assuming you want to create a 16 bit file) although technically the data is usually a 2's compliment signed integer so the values would be -32,768 to 32,767. If you are using Audiotrack for output, you can write them directly with WriteShort. If you are using AudioStreamer, you will need to convert that into two bytes.

Wav files are generally little endian.
 
Upvote 0

Michael Gasperi

Member
Licensed User
Longtime User
Do you think something like this is too ugly

value = 32767*Sin(angle)
data(i+1) = value/256
data(i) = value - data(i+1)*256

streamer.write(data)
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Or:

B4X:
Data(i) = Bit.AND(Value,0xFF)
Data(i+1) = Bit.AND(Bit.ShiftRight(Value,8),0xFF)

How will you control the frequency?
 
Upvote 0

Michael Gasperi

Member
Licensed User
Longtime User
Both nice suggestions.

Frequency comes from how the angle is generated. Knowing the samples are generated at 11025Hz for example, you need to create an angle that steps through one period (or 2*pi) in the right amount of time. Unfortunately, the data array length only fits certain exact multiples of frequencies. For example, with a length of 441 samples, the data plays out in exactly 40ms. If that is one period then you get 25Hz. Put two periods in the 441 samples you get 50Hz etc. I happen to be generating pretty low frequencies, so the slower 11025 sample rate makes sense. Remember the byte size data array has to be twice as big as the samples for mono and 4 times if you have stereo. If you want to infinite precision in the frequency, the process gets complicated.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
the process gets complicated.

the process gets more complicated.:)

Yes, I can see how that would work.

I did try to run it thorough a cycle, I could hear the wave but it was very jittery, presumably you will have to implement some kind of real-time buffering, before starting to write the data.
 
Upvote 0

Michael Gasperi

Member
Licensed User
Longtime User
Here is the guts of what I'm doing. Obviously you don't need to keep recreating the data every 40ms.

Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("1")
streamer.Initialize("streamer", 11025, False, 16, streamer.VOLUME_MUSIC)
timer1.Initialize("timer1", 40)
End Sub

Sub Timer1_Tick
For i = 0 To 1763 Step 4
angle = i * 0.003562
value = 32767*Sin(angle*40) ' left 25*40 = 1000 Hz
data(i+1) = value/256
data(i) = value Mod 256
value = 32767*Sin(angle*40) ' right 25*40 = 1000 Hz
data(i+3) = value/256
data(i+2) = value Mod 256
Next
Do Until streamer.Write(data)
Loop
End Sub
 
Upvote 0
Top