Reading bytes in particular order

Blitz3D Forums/Blitz3D Beginners Area/Reading bytes in particular order

_PJ_(Posted 2010) [#1]
Sorry for the crappy thread title.

The problem I have here ,isn't so much how to do something, but how to do it in a sensible, efficient way.

The principle idea of the code, is to do with mp3 sound data. In the file, the sound data can be either mono or stereo.
In the case of mono sounds, the data is as you'd expect, in consecutive bytes, yet in the case of stereo sound, the bytes alternate between left then right.

This isn't so much of a big deal in itself, but with the data, I wish to draw a kinda waveform image. This reuquires (thanks to the Line command ) needing to track the last and current, or current and next points of data so the line can be drawn between the two. That's where my problems start.

I have tried to read bytes in chunks of 4 at a time, this way, I can capture two bytes worth of data even for a stereo sound (two for each channel). If it's a mono sound, then of course, 4 bytes are captured in this way, so the line drawing is just repeated to draw the additional bytes.

Here's what I have so far, the actual drawing routine and other aspects aren't so relevant to the issue, so don't worry if there's functions which aren't available here, the crux of the matter is really just in the For/Next and reading of the data which is all presented below:


		Local nChannelBytes=(nChannels Shl True)
		Local nChannelStep=nChannelBytes-1
		Dim Bytes(nChannelBytes)
		Local nLastLByte=-1
		Local nLastLX=0
		Local nLastRByte=-1
		Local nLastRX=0
		For nIterByte=0 To (WaveFormResolutionWidth-nChannelStep)
			For nIterReadBytes=0 To (nChannelStep)
				Bytes(nIterReadBytes)=PeekByte(bBank,nIterByte+nIterReadBytes)
				If (nChannels=1)
					If (nLastLByte<1)Then nLastLByte=Bytes(0)
					DrawLine(LeftChannelColour,nLastLX,nIterByte,nLastLByte,Bytes(nIterReadBytes))
					nLastLX=nIterByte+nIterReadBytes
					nLastLByte=Bytes(nIterReadBytes)
				Else
					If (nChannels=2)
						DrawLine(LeftChannelColour,nLastLX,nIterByte,nLastLByte,Bytes(nIterReadBytes))
						nLastLX=nIterByte+nIterReadBytes
						nLastLByte=Bytes(nIterReadBytes)
						If (nIterReadBytes)
							If (nLastLByte<1)Then nLastLByte=Bytes(0)
							DrawLine(RightChannelColour,nLastRX,nIterByte+1,nLastRByte,Bytes(nIterReadBytes+1))
							nLastRX=nIterByte+nIterReadBytes+1
							nLastRByte=Bytes(nIterReadBytes+1)
						End If
					End If
				End If
				nIterReadBytes=nIterReadBytes+nChannels
			Next
			nIterByte=nIterByte+nChannelBytes
		Next


If anyone has any advice on how to smarten/speed this up, I'd be realyl grateful. Thanks :)


Charrua(Posted 2010) [#2]
hi

one aproach should be to get the first sample and then repeat from the second to the last drawing from prvious to current:

Previous = GetNextSample()
for Count=SecondSample to LastSample
Current = GetNextSample
drawline fromPrevious to Current
Previous = Current
next

Juan


_PJ_(Posted 2010) [#3]
The difficult part, is reading the "Previous" and "Next" data in the correct order, since the order changes depending on the channels:

i.e.

MONO:

byte1= Left Channel byte1
byte2= Left Channel byte2
byte3= Left Channel byte3
byte4= Left Channel byte4

STEREO:

byte1= Left Channel byte1
byte2= Right Channel byte1
byte3= Left Channel byte2
byte4= Right Channel byte2

Sorry if i wast being so clear :)

Of course I could write out separate routines depending on the channels, but I would prefer to be able to 'automatically' sort the bytes if you know what I mean?


Charrua(Posted 2010) [#4]
only one byte per sample?
normally the samples 8/16 bits and mono/stereo

any way, i think that is more easy to read if you construct a NextSample function that evaluates mono/stereo and the like and a higher routine that doesn't care about that. isn't it?

be aware of 16 bit samples, they normally are stored lo/hi litle endiand style, so the actual 16 bit value must constructed by: First + Second shl 8, being the first the one in lower memory addres and the Second the next in the up adjacent memory address.

is it necesary to draw a line?, why not simply plot the dots, or draw a vertical line from 0 to SampleValue, in this way you still has a good graph of the wave.

Juan


PowerPC603(Posted 2010) [#5]
You could also create a 2-dimentional array.

Dim ArraySamples(10000, 2)

Read the left channel into ArraySamples(xxx, 1) and the right channel into ArraySamples(xxx, 2).
The xxx is the counter you use to increment the arrayindex after you've read both left and right bytes.

If you want to draw the left channel, you only use ArraySamples(xxx, 1), looping throuhg the entire array and you're done.

So:
byte1 => ArraySamples(1, 1)
byte2 => ArraySamples(1, 2)
byte3 => ArraySamples(2, 1)
byte4 => ArraySamples(2, 2)
byte5 => ArraySamples(3, 1)
byte6 => ArraySamples(3, 2)
byte7 => ArraySamples(4, 1)
byte8 => ArraySamples(4, 2)
byte9 => ArraySamples(5, 1)
byte10 => ArraySamples(5, 2)
...

Use the first index as the byte-counter, use the second index as the channel (1 = left, 2 = right).


_PJ_(Posted 2010) [#6]

be aware of 16 bit samples, they normally are stored lo/hi litle endiand style, so the actual 16 bit value must constructed by: First + Second shl 8, being the first the one in lower memory addres and the Second the next in the up adjacent memory address.

is it necesary to draw a line?, why not simply plot the dots, or draw a vertical line from 0 to SampleValue, in this way you still has a good graph of the wave.



Thanks, Charrua yes the number of bits is important. I'd not considered tht yet (oops!) although the basic format is the same, since the bytes themselves are still ordered left than right in stereo, (then of course, there's spdif 24-bit sounds.... )

so a 16-bit sample would just mean:

MONO
byte 1 - left channel bigendian1
byte 2 - left channel littleendian1

byte 3 - left channel bigendian2
byte 4 - left channel littleendian2

byte 5 - left channel bigendian3
byte 6 - left channel littleendian3

byte 7 - left channel bigendian4
byte 8 - left channel littleendian4

STEREO
byte 1 - left channel bigendian1
byte 2 - left channel littleendian1

byte 3 - right channel bigendian1
byte 4 - right channel littleendian1

byte 5 - left channel bigendian2
byte 6 - left channel littleendian2

byte 7 - right channel bigendian2
byte 8 - right channel littleendian2


________________________________________________

PowerPC -
thanks, that's a really smart way of dealing with it :)