Inline C Arrays help
Re: Inline C Arrays help
I'll have a look in the morning. I was just trying to find a solution for both asm and c backend. You can use it to update the read and write pointers.
Re: Inline C Arrays help
here's a port of the PortAudio Ring buffer, it's lock free but only safe for single producer consumer threads.
Code: Select all
; * Portable Audio I/O Library
; * Ring Buffer utility.
; *
; * Author: Phil Burk, http://www.softsynth.com
; * modified For SMP safety on Mac OS X by Bjorn Roche
; * modified For SMP safety on Linux by Leland Lucius
; * also, allowed For const where possible
; * modified For multiple-byte-sized Data elements by Sven Fischer
; *
; * Note that this is safe only For a single-thread reader And a
; * single-thread writer.
; *
; * This program uses the PortAudio Portable Audio Library.
; * For more information see: http://www.portaudio.com
; * Copyright (c) 1999-2000 Ross Bencina And Phil Burk
; *
; * Permission is hereby granted, free of charge, To any person obtaining
; * a copy of this software And associated documentation files
; * (the "Software"), To deal in the Software without restriction,
; * including without limitation the rights To use, copy, modify, merge,
; * publish, distribute, sublicense, And/Or sell copies of the Software,
; * And To permit persons To whom the Software is furnished To do so,
; * subject To the following conditions:
; *
; * The above copyright notice And this permission notice shall be
; * included in all copies Or substantial portions of the Software.
; *
; * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
; * EXPRESS Or IMPLIED, INCLUDING BUT Not LIMITED To THE WARRANTIES OF
; * MERCHANTABILITY, FITNESS For A PARTICULAR PURPOSE And NONINFRINGEMENT.
; * IN NO EVENT SHALL THE AUTHORS Or COPYRIGHT HOLDERS BE LIABLE For
; * ANY CLAIM, DAMAGES Or OTHER LIABILITY, WHETHER IN AN ACTION OF
; * CONTRACT, TORT Or OTHERWISE, ARISING FROM, OUT OF Or IN CONNECTION
; * With THE SOFTWARE Or THE USE Or OTHER DEALINGS IN THE SOFTWARE.
; */
;
; /*
; * The text above constitutes the entire PortAudio license; however,
; * the PortAudio community also makes the following non-binding requests:
; *
; * Any person wishing To distribute modifications To the Software is
; * requested To send the modifications To the original developer so that
; * they can be incorporated into the canonical version. It is also
; * requested that these non-binding requests be included along With the
; * license above.
; */
;
; Ported to PB 6.0 idle x86/x64 asm and cbackend
Structure RingBuffer_Ar
e.a[0]
EndStructure
Structure RingBuffer
stop.i
bufferSize.i
writeIndex.i
readIndex.i
bigMask.i
smallMask.i
elementSizeBytes.i
*buffer.Ringbuffer_Ar
EndStructure
Macro FullMemoryBarrier()
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!mfence
CompilerElse
!__sync_synchronize();
CompilerEndIf
EndMacro
Macro WriteMemoryBarrier()
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!sfence
CompilerElse
!__sync_synchronize();
CompilerEndIf
EndMacro
Macro ReadMemoryBarrier()
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
!lfence
CompilerElse
!__sync_synchronize();
CompilerEndIf
EndMacro
Procedure InitializeRingBuffer(*rbuf.RingBuffer,elementSizeBytes,elementCount)
If(((elementCount-1) & elementCount) <> 0)
ProcedureReturn -1
EndIf
*rbuf\bufferSize = elementCount
*rbuf\buffer = AllocateMemory(elementCount*elementSizeBytes)
*rbuf\bigMask = (elementCount*2)-1
*rbuf\smallMask = (elementCount)-1
*rbuf\elementSizeBytes = elementSizeBytes
ProcedureReturn *rbuf\buffer
EndProcedure
Procedure FreeRingBuffer(*rb.RingBuffer)
If *rb
If *rb\buffer
FreeMemory(*rb\buffer)
*rb\buffer = #Null
EndIf
EndIf
EndProcedure
Procedure GetRingBufferReadAvailable(*rb.RingBuffer)
ProcedureReturn((*rb\writeIndex - *rb\readIndex) & *rb\bigMask)
EndProcedure
Procedure GetRingBufferWriteAvailable(*rb.RingBuffer)
ProcedureReturn(*rb\bufferSize - GetRingBufferReadAvailable(*rb))
EndProcedure
Procedure FlushRingBuffer(*rb.RingBuffer)
*rb\writeIndex = 0
*rb\readIndex = 0
EndProcedure
Procedure GetRingBufferWriteRegions(*rb.RingBuffer,elementCount,*dataPtr1.integer,*sizePtr1.integer,*dataPtr2.integer,*sizePtr2.integer )
Protected index.i, available.i
available.i = GetRingBufferWriteAvailable(*rb)
If elementCount > available
elementCount = available
EndIf
index = (*rb\writeIndex & *rb\smallMask)
If(index + elementCount) > *rb\bufferSize
firstHalf = *rb\bufferSize - index
*dataPtr1\i = @*rb\buffer\e[index * *rb\elementSizeBytes]
*sizePtr1\i = firstHalf
*dataPtr2\i = @*rb\buffer\e[0]
*sizePtr2\i = elementCount - firstHalf
Else
*dataPtr1\i = @*rb\buffer\e[index * *rb\elementSizeBytes]
*sizePtr1\i = elementCount
*dataPtr2\i = #Null
*sizePtr2\i = 0
EndIf
If available
FullMemoryBarrier()
EndIf
ProcedureReturn elementCount
EndProcedure
Procedure AdvanceRingBufferWriteIndex(*rb.RingBuffer,elementCount.i)
Protected index,*ptr
WriteMemoryBarrier()
*rb\writeIndex = (*rb\writeIndex + elementCount) & *rb\bigMask
ProcedureReturn *rb\writeIndex
EndProcedure
Procedure GetRingBufferReadRegions(*Rb.RingBuffer,elementCount,*dataPtr1.integer,*sizePtr1.integer,*dataPtr2.integer,*sizePtr2.integer)
Protected index.i,firsthalf.i,available.i
available.i = GetRingBufferReadAvailable(*rb)
If( elementCount > available )
elementCount = available
EndIf
index = (*rb\readIndex & *rb\smallMask)
If((index + elementCount) > *rb\bufferSize )
firstHalf = *rb\bufferSize - index
*dataPtr1\i = @*rb\buffer\e[index * *rb\elementSizeBytes]
*sizePtr1\i = firstHalf
*dataPtr2\i = @*rb\buffer\e[0]
*sizePtr2\i = elementCount - firstHalf
Else
*dataPtr1\i = @*rb\buffer\e[index * *rb\elementSizeBytes]
*sizePtr1\i = elementCount
*dataPtr2\i = 0
*sizePtr2\i = 0
EndIf
If( available )
ReadMemoryBarrier()
EndIf
ProcedureReturn elementCount
EndProcedure
Procedure AdvanceRingBufferReadIndex(*rb.RingBuffer,elementCount)
FullMemoryBarrier()
*rb\readIndex = (*rb\readIndex + elementCount) & *rb\bigMask
ProcedureReturn *rb\readIndex
EndProcedure
Procedure WriteRingBuffer(*rb.RingBuffer,*Data,elementCount)
Protected size1, size2, numWritten
Protected data1, data2
numWritten = GetRingBufferWriteRegions(*rb,elementCount,@data1, @size1, @data2, @size2)
If( size2 > 0 )
CopyMemory(*Data,data1,size1 * *rb\elementSizeBytes)
*data + (size1 * *rb\elementSizeBytes)
CopyMemory(*Data,data2,size2 * *rb\elementSizeBytes)
Else
CopyMemory(*Data,data1, size1 * *rb\elementSizeBytes )
EndIf
AdvanceRingBufferWriteIndex(*rb,numWritten)
ProcedureReturn numWritten
EndProcedure
Procedure ReadRingBuffer(*rb.RingBuffer,*Data,elementCount)
Protected size1, size2, numRead
Protected data1, data2
numRead = GetRingBufferReadRegions(*rb,elementCount,@data1,@size1,@data2,@size2 )
If( size2 > 0 )
CopyMemory(data1,*data,size1 * *rb\elementSizeBytes )
*Data + size1 * *rb\elementSizeBytes
CopyMemory(data2,*Data,size2 * *rb\elementSizeBytes )
Else
CopyMemory(data1,*Data,size1 * *rb\elementSizeBytes )
EndIf
AdvanceRingBufferReadIndex(*rb,numRead)
ProcedureReturn numRead
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Procedure Producer(*RB.RingBuffer)
Protected num
Dim inputs.f(64)
Repeat
For a = 0 To 63
inputs(a) = ct
ct+1
Next
num = WriteRingBuffer(*RB,@inputs(0),64) ;write 64 elements to the ring if full it will return 0
Debug "num write " + Str(num)
Delay(Random(100,20))
Until *RB\stop
EndProcedure
Procedure Consumer(*RB.RingBuffer)
et= ElapsedMilliseconds() + 10000
Dim outputs.f(64)
Repeat
num = ReadRingBuffer(*RB,@outputs(0),64) ;read 64 elements off ring if empty it will return 0
Debug "num read " + Str(num) + " " + StrF(outputs(0),3)
Delay(Random(100,20))
Until ElapsedMilliseconds() > et
*rb\stop = 1 ;stop buffering
EndProcedure
Global RB.RingBuffer ;decalre a RB
InitializeRingBuffer(@RB,SizeOf(float),1024) ;set the size in bytes of elements and the number or elements
t1 = CreateThread(@Producer(),@RB) ;create writer thread
t2 = CreateThread(@consumer(),@RB) ;create reader thread
WaitThread(t2)
CompilerEndIf
Re: Inline C Arrays help
this might work for you it's simulating what you need to do through the ringbuffer in previous post using two call backs one for thge input on your external sound card and the other on the on board sound card
Code: Select all
XIncludeFile "ringbuffer.pbi"
ImportC "portaudio_x64.lib" : EndImport
!//#include E:\andrews\pbstuff\paintsound\portaudio\portaudio.h; path to portaudio.h
ProcedureC InputCallback(*in.float,*out.float,framesPerBuffer,*timeInfo,statusFlags,*rb)
WriteRingBuffer(*rb,*in,framesPerBuffer)
EndProcedure
ProcedureC OutputCallback(*in.float,*out.float,framesPerBuffer,*timeInfo,statusFlags,*rb)
ReadRingBuffer(*rb,*out,framesPerBuffer)
EndProcedure
OpenConsole()
!#define SAMPLE_RATE (44100)
!#define PA_SAMPLE_TYPE paFloat32
!PaStreamParameters inputParameters;
!PaStreamParameters outputParameters;
!PaStream *streamin;
!PaStream *streamout;
Global err,pinputcb,poutputcb,samplesize ;
samplesize = 256*2*SizeOf(float)
pinputcb= @InputCallback()
poutputcb = @OutputCallback()
Global rb.ringbuffer
InitializeRingBuffer(@rb,8,8192)
!v_err = Pa_Initialize();
If err <> 0
Goto error;
EndIf
!inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
!if (inputParameters.device == paNoDevice) {
Debug "Error: No default input device."
Goto error;
!}
!inputParameters.channelCount = 2; /* stereo input */
!inputParameters.sampleFormat = PA_SAMPLE_TYPE;
!inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device )->defaultLowInputLatency;
!inputParameters.hostApiSpecificStreamInfo = 0;
!outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
!if (outputParameters.device == paNoDevice) {
Debug "Error: No Default output device."
Goto error;
!}
!outputParameters.channelCount = 2; /* stereo output */
!outputParameters.sampleFormat = PA_SAMPLE_TYPE;
!outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
!outputParameters.hostApiSpecificStreamInfo = 0;
!v_err = Pa_OpenStream(&streamin,&inputParameters,0,SAMPLE_RATE,v_samplesize,0,v_pinputcb,&v_rb);
If err <> 0
Goto error;
EndIf
!v_err = Pa_OpenStream(&streamout,0,&outputParameters,SAMPLE_RATE,v_samplesize,0,v_poutputcb,&v_rb);
If err <> 0
Goto error;
EndIf
!v_err = Pa_StartStream( streamin );
If err <> 0
Goto error;
EndIf
!v_err = Pa_StartStream( streamout );
If err <> 0
Goto error;
EndIf
PrintN("Hit ENTER to stop program.");
Input()
!v_err = Pa_CloseStream( streamin );
If err <> 0
Goto error;
EndIf
!v_err = Pa_CloseStream( streamout );
If err <> 0
Goto error;
EndIf
!Pa_Terminate();
End
error:
!Pa_Terminate();
Re: Inline C Arrays help
Thanks idle, i'll check it out today. You should have a donation link. I want to buy you a beer
Re: Inline C Arrays help
It works flawlessly. Threadsafe needs to be switched on and the ringbuffer size must be a power of 2. This has solved all of my problems and simplified my code considerably. Thanks again idle.
Re: Inline C Arrays help
Glad it solved your problem I also needed a better ringbuffer and that one is pretty good. Thanks for the beer.