Ooops
October 16, 2021, 06:43:50

Author Topic: My Music Editor  (Read 6280 times)

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #45 on: July 08, 2021, 18:39:21 »

I took a rest from programming returned back not long ago..

OK now Im trying to learn Audio recording..

I did a small app for recording and testing..

Ive managed to record audio just fine..
but now that I have the Sample:Byte ptr
I have no Idea how to read from it.
how do I access a Byte ptr? Like Peek and Poke on commodore 64?


-------------------------------------

OK after experimenting with Byte ptr ive managed to start understanding how to use it..

Seems you access it like Arrays..  ByePtr[AddressInBytes]


Question 2:

When i do playsound and save the channel it played on
and when i ask is channelplaying.. it wont give a false reply when the sample is suppose to have ended..
how can that be ?




« Last Edit: July 24, 2021, 01:12:41 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #46 on: July 09, 2021, 07:27:40 »
Are you using OpenAL or MiniAudio for recording?

Depending on the format of the recording you would better use Byte Ptr or Short Ptr for receiving the true values.

simply add a new pointer if needed:
Code: BlitzMax
  1. ShortSample: Short Ptr = Short Ptr(MyRecording.Samples)
  2. For local i:Int=0 to MyRecording.length/2-1
  3.    Print ShortSample[i]
  4. Next
If you recorded in 16bit the MyRecording.length still shows you the length in bytes. So you have to divide by 2.

If you only want to save the recorded samples you need not to care about the correct pointers. But if you want to process or check the recording signal you need the true values:

If you recorded 8bit Byte Ptr is the best, but you have to substract 128 to get the real values. The reason is that the Zero-Value is defined as 128 in 8bit-Streams.
You can use this function:
Code: BlitzMax
  1. Function ByteToInt:Int( s:Int )
  2.     Return s-128
  3. End Function


If you recorded 16bit Short Ptr is the best, but you have to transform the values from Unsigned SHORT to Signed INT to get the real values. The reason is that  BlitzMax has no Signed SHORT variable type.

You can use this function:
Code: BlitzMax
  1. Function ShortToInt:Int( s:Int )
  2.     Return (s Shl 16) Sar 16
  3. End Function


After you transfered the samples values to true values you could do things like adjusting the volume of a recording, etc...



If you use MiniAudio and record with 32bit you could directly work with the values if you use the correct pointer Int Ptr or Float Ptr.
« Last Edit: July 12, 2021, 01:44:06 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #47 on: July 09, 2021, 12:26:15 »
Im using Open AL

Im trying to read the volume while recording but it wont let..

now ill try to cut half of the sample and see if it works.

ill put my little app here soon for investigation


OK i managed to cut a sample to half.. I mean clone half section to its own other half section

this is my code.. feel free to tell me whats wrong

Code: [Select]
Function CutSample(Sample:TAudioSample Var, From = 0, Till = 0)
Local T:TAudioSample, KeepSize, HalfLength

KeepSize = Sample.length

HalfLength = Sample.length / 2

T = CreateAudioSample(KeepSize, MO.SAMPLE_RATE, SF_STEREO16LE)

MemCopy(T.samples, Sample.samples, Sample.length)

For Local I = HalfLength To Sample.length
Sample.samples[I - HalfLength] = T.samples[I]
Next

End Function


once again.. i have problem telling when the playing has ended.. of the audio sample.. since the channelplaying keeps showing as if its still playing for some reason

im trying to display the sample and thats what i did. and it aint working properly

Code: [Select]
Function DisplayRecordedSample(MySample:MySample_Type, Xpos:Float = 0, Ypos:Float = 0)
Local Ratio:Float, SampleHeight:Float

Ratio = SEWidth / MySample.Sample.length

xSetBuffer(xImageBuffer(SE_Image))

xColor(0, 255, 0)

SampleHeight = Math.FitValue(MySample.Sample.samples[MySample.LengthInBytes - 2], 256, SEHeight)

xRect(MySample.LengthInBytes * Ratio, SEHeight - SampleHeight, 1, SampleHeight, True)

   'Frame
xColor(255, 0, 0)
xRect(0, 0, SEWidth - 1, SEHeight - 1)

xSetBuffer(xBackBuffer())

End Function
« Last Edit: July 09, 2021, 16:25:24 by Hardcoal »
...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #48 on: July 10, 2021, 20:35:27 »
Anyway when I record a sample.. and than replay.. it keeps thinking its being played for at least double the time for some reason..
but when i save the sample and reload it.. it stops exactly at the end..
I dont know why..

I also have no Idea how to display the Wave of the sample.. :( annoying
« Last Edit: July 10, 2021, 22:12:36 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #49 on: July 11, 2021, 08:36:05 »
It looks like you are working with a library I dont know.

some of your functions are not native BlitzMax functions.

If you use regular TAudioSample and SF_STEREO16LE the values are UNSIGNED SHORT in BlitzMax, but SIGNED SHORT in reality. To get a value which you can process you have to transform it to INTEGER

second: When you process SF_STEREO16LE you have to care about the frame size of 4 bytes. Each sample is 4 bytes long:
Code: [Select]
|high left | low left | high right | low right |This means your cuts or moves are only allowed on positions which are multiples of 4. If you not care about this may cause noise sound or mix-ups of left and right channel.
Code: [Select]
HalfLength = (Sample.length / 2) Mod 4 '!!!!!
What is the type MySample_Type. Thats a non BlitzMax standard audio type? Perhaps already converted to INT? We must know this to give you the best advise.

To get a graphic you have to calculate with the real samples values. With original TAudioSample you need to convert each from UNSIGNED SHORT to INTEGER:
Code: [Select]
    Function ShortToInt:Int( s:Int )
        Return (s Shl 16) Sar 16
    End Function

Now you can shrink the values by dividing /256 and you will get values from -256 to 256 which fit to the screen. To manage the horizontal size of the TAudioSample you could use only every hundredth sample. This would mean that only 441 x-values remain per second.




See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #50 on: July 11, 2021, 10:06:30 »
OK midi master im now on it and testing what youre saying .. Thanks

MySample_Type is just something I made ..
it holds TaudioSample.

midimaster im using the code you adviced for me..

nothing else

here are my includes

Code: [Select]
Import vertex.openal
Import brl.standardio

Import brl.audiosample
Import brl.audio

Import brl.glmax2d
Import brl.reflection
Import brl.retro
Import brl.WavLoader
Import brl.directsoundaudio


btw midimaster i saw you on a blitzmax german site.. i tried to register but it didnt work



« Last Edit: July 11, 2021, 20:20:41 by Hardcoal »
...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #51 on: July 11, 2021, 20:38:04 »
I cant make it work.. This is the function the suppose to display then sample while recording..

Code: [Select]
Function DisplayRecordedSample(MySample:MySample_Type, Xpos:Float = 0, Ypos:Float = 0)
Local Ratio:Float, SampleHeight

Ratio = SEWidth / MySample.Sample.length

xSetBuffer(xImageBuffer(SE_Image))

xColor(0, 255, 0)

    If MO.LengthCounterInBytes / 4 = Floor(MO.LengthCounterInBytes / 4) Then
Local TI =MySample.Sample.samples[MO.LengthCounterInBytes - 4]
TI = (TI Shl 8) + MySample.Sample.samples[MO.LengthCounterInBytes - 3]
SampleHeight = Math.FitValue(TI, 65536, SEHeight)
End If

Local CurrentX:Float = MO.LengthCounterInBytes * Ratio

xRect(PreviousDX, SEHeight - SampleHeight, CurrentX - PreviousDX, SampleHeight, True)

PreviousDX = CurrentX

xSetBuffer(xBackBuffer())

End Function


Function FitValue:Float(Value:Float, PeekValue:Float, NewFrame:Float)
Return NewFrame / PeekValue * Value
End Function


it suppose just to show the volume of the sample inside an Image sized 600*100
but instead it only shows lines even when its not making sound

the command FitValue is just mine.. to set the value into a 256 pixels Frame Top height limit. so dont mind it..

I understood what you said about the structure of the Sample.. but i still cant read it correctly..
ill keep working on it

Im trying to display only one side of the sample . i dont try to display stereo atm.
I wanted to pass faze one before I try Stereo . but I fail at this too.. and i dont know why



i also tried this for display not in real time while sampling, but later..

Code: [Select]
Function DisplayRecordedSampleLater(MySample:MySample_Type)
Local Ratio:Float

Ratio = SEWidth / MySample.Sample.length

xSetBuffer(xImageBuffer(SE_Image))

xColor(0, 255, 0)

For Local I = 0 To MySample.sample.length Step 4
Local High = MySample.Sample.samples[I]
Local Low = MySample.Sample.samples[I + 1]
Local Combined = high Shl 8 + Low
Local SampleHeight = Math.FitValue(Combined, 65536, SEHeight)
xRect(I * Ratio, SEHeight - SampleHeight, 1, SampleHeight, True)
Next

xSetBuffer(xBackBuffer())

End Function

« Last Edit: July 11, 2021, 21:19:19 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #52 on: July 12, 2021, 01:38:03 »
Again! If you use SF_STEREO16LE you should use a SHORT pointer instead of a BYTE Pointer

It is a good idea first to start testing your code not in real time but with a given TAudioSample afterwards.
The capture-device will return values from -32768 to +32768, but BlitzMax Short Ptr will show them as value from 0 to 65536 which is wrong. After using the function ShortToInt() the Value are correct but need to be INTEGER.

Only with this INTEGER you can start your calculations for display.
 
BlitzMax 1.50:
Code: BlitzMax
  1. Local Audio:TAudioSample
  2. RealPointer: Short Ptr = Short Ptr(Audio.Sample)
  3.  
  4. ' for read MONO or read all of STEREO use this:
  5. For local i%=0 to Audio.Length-1
  6.      local Value% = RealPointer[i]
  7.      Value =  ShortToInt( Value )  
  8. Next
  9.  
  10. ' for listen to one channel of STEREO use this:
  11. For local i%=0 to Audio.Length-1 Step 2
  12.      local LeftValue% = RealPointer[i]
  13.      LeftValue =  ShortToInt( LeftValue )
  14.  
  15.      local RightValue% = RealPointer[i+1]
  16.      RightValue =  ShortToInt( RightValue )    
  17. Next
  18.  
  19. Function ShortToInt:Int( s:Int )
  20.         Return (s Shl 16) Sar 16
  21.     End Function
  22.  


Here a runnable Example for you:
(uses the audio-file TestABC.OGG from attachment here)
Code: BlitzMax
  1. SuperStrict
  2. Graphics 1200,600
  3. Global Audio:TAudioSample=LoadAudioSample("testabc.ogg")
  4.  
  5. Print " HERTZ = " + Audio.Hertz
  6. Print "FORMAT = " + Audio.Format + " (SF_MONO16LE)"
  7. Print "LENGTH = "  +Audio.Length
  8. 'Print Audio.Samples
  9. Global RealPointer:Short Ptr = Short Ptr(Audio.Samples)
  10. Global Start%=0
  11. Repeat
  12.         Cls
  13.                 For Local I%= 0 To 1200
  14.                         Local Value% = RealPointer[(i+Start)*5]
  15.                          value = ShortToInt( Value)
  16.                         DrawRect i, 300,1,Value/100
  17.                 Next
  18.         Flip 1
  19.         Start=Start + 5
  20. Until AppTerminate()
  21.  
  22.  
  23. Function ShortToInt:Int( s:Int )
  24.         Return (s Shl 16) Sar 16
  25. End Function
  26.  
  27.  
« Last Edit: July 12, 2021, 01:41:06 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #53 on: July 12, 2021, 03:50:13 »
I thought Short is a Byte.. :S

A) Why do you need a minus value in a sound wave? I didnt even expect this So minus means Left side?

B) why do you Step 5 when you said that each sample is 4 Bytes?
« Last Edit: July 12, 2021, 04:37:48 by Hardcoal »
...

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #54 on: July 12, 2021, 07:48:55 »
I thought Short is a Byte.. :S
signed SHORTs are signed 16bit integer with 1sign-bit and 15 value bits (values from -32768 to +32768)
BYTES are 8bit integer always unsigned, so all 8bit are value bits (values from 0 to 255)


Quote
A) Why do you need a minus value in a sound wave?
The speakers are driven by AC voltage: With V=+1 the speaker is push ahead, with V=-1 the speaker is pushed back. Think of a sinus-curve which also runs from 0 (0°) to 1 (90°) back to 0 (180°) then to -1 (270°) and back to the beginning.

Quote
I didnt even expect this So minus means Left side?
No, the channels are independent, each channel has its own SHORT. In a TAudioSample they are sorted in Frames. Means all SHORTS belonging to the same time stamp are close together:
Code: [Select]
| Left 1 | Right 1 || Left 2 | Right 2 || Left 3 | Right 3 || ....|
Would the recording have 4 channels:
Code: [Select]
| ChA 1 | ChB 1 |ChC 1 | ChD 1 || ChA 2 | ChB 2 |ChC 2 | ChD 2 || ChA 3 | ChB 3 |....|


Quote
B) why do you Step 5 when you said that each sample is 4 Bytes?
In a MONO recording the correct step would be 1 to reach all samples values, because a SHORT PTR already jumps 16bit ahead each step:

Code: [Select]
SHORT PTR    RAM ADRESS
--------------------------
[0]          12345678
[1]          12345680
[2]          12345682
[3]          12345684
[4]          12345686
....

The 5 is related to the fact that in a recording the values are not changing that fast and we need not to to display them all. Its something like a "zoom factor" for the display not to show every sample but only every 5th. You can change the 5 to a 1 to get a more detailed view into the audio. Or change the 5 to a 500 to get a rough overview over the whole recording.

In a 12kHz-Recording:..
Code: [Select]
  1 means each 1/12000sec is a pixel, 1200 pixels show a time of 0.1sec
  5 means each  1/2400sec is a pixel, 1200 pixels show a time of 0.5sec
500 means each    1/24sec is a pixel, 1200 pixels show a time of 50 sec
« Last Edit: July 12, 2021, 07:53:28 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #55 on: July 12, 2021, 07:50:55 »
sorry double post
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #56 on: July 12, 2021, 17:05:40 »
I never knew a speaker vibrate on both directions .. ive always thought it only either produce magnetic field or not..
but now i do..
...

Offline Hardcoal

  • Hero Member
  • *****
  • Posts: 743
  • nothing is personal
Re: My Music Editor
« Reply #57 on: July 12, 2021, 19:51:17 »
Although I still didnt quite understand how you read the data..
I did fix your example..
Because it got stuck

Code: [Select]
blitzmax

Strict

Const SWidth:Int = 1200
Const SHeight:Int = 600

Graphics (SWidth, SHeight)

Global AudioSample:TAudioSample = LoadAudioSample("Mine2.wav")
 
Print "HERTZ = " + AudioSample.Hertz
Print "FORMAT = " + AudioSample.Format + " (SF_MONO16LE)"
Print "LENGTH = "  +AudioSample.Length

Global RealPointer:Short Ptr = Short Ptr(AudioSample.Samples)

Const StepSize:Int = 5

Global Counter:Int = 0

Repeat
     Cls
    'Draws all wave
         For Local I:Int = 0 To SWidth  'This will Display from Edge To Edge what it can
            Local Value:Int = RealPointer[(I + Counter) * StepSize]
            Value = ShortToInt(Value)
            DrawRect (I, SHeight / 2, 1, Value / 100)
         Next
     Flip 1

If KeyDown(KEY_SPACE) = False Then Counter = Counter + StepSize

Until SWidth + Counter * StepSize >= AudioSample.length

Function ShortToInt:Int( s:Int )
        Return (s Shl 16) Sar 16
End Function

Ive managed to display the Wave properly

But now I want when I play the Sample to see a line the represent the location in the Sample.
But when you use PlaySound you dont get any information of the location of the playing..

So i can count time manually .. or is it a way to read to current location of the PlaySound, somehow?

Anyway i still didnt get the wave thing correctly, since what I display after recording is not the same like what i display when I load what I recorded..
« Last Edit: July 12, 2021, 19:56:17 by Hardcoal »
...

Offline iWasAdam

  • Hero Member
  • *****
  • Posts: 2477
Re: My Music Editor
« Reply #58 on: July 12, 2021, 19:57:08 »
Bytes can actually be signed or unsigned

The minus values are actually irrelevant they nearly help things. Speakers operate on a +- voltage system, but can be 0 aligned.

The computer storage can be anything - it’s the os and the hardware that does the actuall transform to something an amp would understand - usually some form of optical isolated digital to analogue conversion.

So. The computer storage and manipulation can be any format it wants - it’s the low level stuff that does the actual conversion.

Now…. Different audio systems (open all, etc) can use similar or completely different mechanisms.

Remember also that signed values are actually just the numbers, and cen be dealt directly as such. Using minus values is just a way to make it simple for humans to use…

The best way to think about audio is to understand what the driver wants. What you are happy with, and work out how to do the conversion when you require.

My personal suggestion is to use a signed float as the internal system storage- it makes everything simple and quick

Offline Midimaster

  • Sr. Member
  • ****
  • Posts: 363
    • Midimaster Music Education Software
Re: My Music Editor
« Reply #59 on: July 13, 2021, 00:59:40 »
...But now I want when I play the Sample to see a line the represent the location in the Sample.
But when you use PlaySound you dont get any information of the location of the playing..

But you can guess on which SamplePosition the PlaySound is. When we set aside, that we have latency the position in the audio is relative to the time that passed since we started the audio with PlaySound.

PlaySound plays HERTZ frames per seconds. Means in MONO:
Code: [Select]
Local Audio:TAudioSample
RealPointer: Short Ptr = Short Ptr(Audio.Sample)
Music:TSound = LoadSound(Audio)
PlaySound Music
StartTime:Int=Millisecs()
Repeat
     Position =  (Millisecs()-StartTime)*Audio.Hertz/1000
     ActSample = ShortToInt( RealPointer[Position] )
Until AppTerminate()


Quote
Anyway i still didnt get the wave thing correctly, since what I display after recording is not the same like what i display when I load what I recorded..
You need to explane more precise what the problems are or how you notice them. There should not be any difference.

Or send us the actual code snipplet for both.


Bytes can actually be signed or unsigned
Of course they can, what I want to say is that in AUDIO-CAPTURE the SF_MONO8 is defined UNSIGNED with 128=ZERO. That is completely different from the other formats which are defined SIGNED and use a SIGN-BIT. Without this knowledge (how to transform) he cannot calculate (or paint) with the values.

And it matters that the SF_MONO16 is SIGNED but misinterpreted by BlitzMax. Without this knowledge he cannot calculate (or paint) with the values.

Hardcoal has to consider this in both of his functions: DisplayRecordedSample() and DisplayRecordedSampleLater()

At the moment I guess that Hardcoal is using SF_STEREO16LE to capture the audio.
« Last Edit: July 13, 2021, 01:02:36 by Midimaster »
See my current project on PlayStore: 20Tracks-Audio-Player https://play.google.com/store/apps/details?id=midimaster.twentytrackd

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal