My Music Editor

Started by Hardcoal, May 24, 2021, 23:57:24

Previous topic - Next topic

Hardcoal

Im not sure i made a topic about it so if i have i apologize for making double topics..
but i think i only mentioned it on an already existing topic..
(this time im marking this post)

anyway, im doing multiple projects as usual. each time jumping from one to another just not to get bored, and from other reasons, i wont get into now.

Ok, MY question is.. how do I control a VST synthesizer from my midi input.

I already know how to read midi input into blitzmax.. but how do i transmit it to the VST?.

I may have asked this question about the VST before, but i dont remember getting a clear answer.
(I apologize if i missed)

Second question.
how can  i control the latency of my Driver..
how to i change its interface from blitzmax like 192,000hz and so on.

thanks
Code

Midimaster

MIDI control

This depends on the syntax each Synthi uses. A lot of them are controlled by Control Changes Messages. And some can only be controled by SYSTEM EXCLUSIV Messages, Both message types are standard members of the MIDI protocol. CC are short messages and often used to turn knobs or switch effects on/off . SYSEX have a individual length and individual syntax. Only the header and the last message byte are part of the MIDI protocol. Between this two points SYSEX do what the want .This is often used for transfer big blocks of information (soundbank, update, etc..)

Each instruments should have a MIDI IMPLEMENTATION TABLE or MANUAL, where you hopefully find the detailed syntax.

Latency
Latency is not a "feature" but a "problem". If we could "control" it, we always would set it to zero! The only chance you have is to use devices which have a low latency. For example my PRESONUS mixer has 5msec latency when recording 24 tracks to a computer. Expensive!
Or ASIO is a technology made by steinberg, which offers drivers below 30msec for all instrument, that can handle ASIO. WASAPI is the answer from microsoft to ASIO. not so good but better than old MME or DIRECTX ever was. On MAC you have better latency by default, on LINUX I dont know.

BlitzMax cannot handle ASIO or WASAPI by default. The build in FreeAudio-Driver does not know modern Backends like WASAPI and comes along with latency <130msec.

That is one of the reasons why I write this MiniAudio-Wrapper. This open the low latency-world for BlitzMax. Or enables your wish to use 192kHz (what is not really helpful, if other parameters stay low quality).

You should always find optimized set of parameters. So "48kHz with 32bit-float and 20msec latency when using 8 tracks" is a more useful set.


...back from Egypt

Hardcoal

#2
I see ok thanks for now midi master.
I actually wanted one vst synth to workp for getting sane sounds.
Im not planning on a full music editing software.
Ill find a solution, that's for sure.

With my external audio card i get to 1. 3ms latency.

Im not looking for a complete midi control.
Only keyboard keys and maybe volume and modulation.

I already encountered the diff between one tool that doesn't properly work in midi.
But i will fix it.
It's fun anyway when things work
So im not suffering

(all in good time), Cheers
Code

Hardcoal

I was trying to compile miniaudio and i got this error

►mima.miniaudio was scheduled to next iteration
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c: In function 'MM_GetContext':
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:100:5: error: 'for' loop initial declarations are only allowed in C99 mode
     for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
     ^
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:100:5: note: use option -std=c99 or -std=gnu99 to compile your code
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:107:20: error: redefinition of 'iDevice'
     for (ma_uint32 iDevice = 0; iDevice < captureCount; iDevice += 1) {
                    ^
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:100:20: note: previous definition of 'iDevice' was here
     for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
                    ^
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:107:5: error: 'for' loop initial declarations are only allowed in C99 mode
     for (ma_uint32 iDevice = 0; iDevice < captureCount; iDevice += 1) {
     ^
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c: In function 'MM_DecodeMP3':
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:158:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for (int i=0; i<frameCount; i++){
  ^
Build Error: failed to compile D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c
►►►►mima.miniaudio was not built. See error information on latest attempt.


the other mod was compiled successfully
Code

Midimaster

did you really use BlitzMax NG?
...back from Egypt

Hardcoal

ohhh its for blitzmax ng :S no i havnt..
I cant use my project in blitzmaxng

Code

Midimaster

#6
They code line you reported is written by me and not part of the mainfile miniaudio.h.

I had a look into the main code miniaudio.h and it looks like  the author kept all his code compatible to C89 standard.
There is a difference in using FOR/NEXT loop in C-versions of 1989 compared to 1999. In C99 it is allowed to define a variable i inside the FOR-loop:
C99
for (int i=0;i<10;i++) {
}


In C89 it had to be written like this:
C89
int i;
for (i=0;i<10;i++) {
}


So if the 2 code lines you reported are the only one, which made problems I can change it to a C89 standard too. Then maybe miniaudio runs also under BlitzMax 1.51.

but you have to switch on Multi-Threading.

There are only 3 changes necessary in midiaudiowrapper.c. This are the modifications:

before:
//line 99
    printf("list of playback devices: \n");
    for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
....
//line 106
    printf("list of capture devices: \n");
    for (ma_uint32 iDevice = 0; iDevice < captureCount; iDevice += 1) {
...
//line 127
    int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
    for (int i=0; i<frameCount; i++){
...


must become....

after:
//line 99
    printf("list of playback devices: \n");
    ma_uint32 iDevice;
    for (iDevice = 0; iDevice < playbackCount; iDevice += 1) {
....
//line 106
    printf("list of capture devices: \n");
    for (iDevice = 0; iDevice < captureCount; iDevice += 1) {
...
//line 127
    int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
    int i;
    for (i=0; i<frameCount; i++){
...



The attachment is the replacement for miniaudiowrapper.c:
...back from Egypt

Hardcoal

#7
thanks midi master. I owe you, but now i get this error

►mima.miniaudio was scheduled to next iteration
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s: Assembler messages:
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:3166: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:84145: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:84146: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:84147: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:87107: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:87747: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:87961: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:88601: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:88697: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:89337: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:89433: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:90073: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:90169: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:90809: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:98310: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:98950: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:99046: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:99686: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:99782: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:100422: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:100518: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:101158: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:102784: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:103424: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:105729: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:106338: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:112628: Error: no such instruction: `lzcntl %eax,%eax'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:139777: Error: junk at end of line, first unrecognized character is `,'
C:\Users\Hardc\AppData\Local\Temp\ccrFlFND.s:139924: Error: junk at end of line, first unrecognized character is `,'
Build Error: failed to compile D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c
►►►►mima.miniaudio was not built. See error information on latest attempt.
Code

Midimaster

this does not look as nice as it did last time. My C-skills are not very good, so now I have to ask one of the experts Derron, Col or IWasAdam. I will forward your report to my thread "how to write a wrapper".

by the way... what is the reason you need to use BlitzMax 1.51 still?
...back from Egypt

Hardcoal

I use blitzmax 1.51 because im using xors3d..

I tried to move to other platforms and each time I got upset over something else..
I really tried..

Ill try again soon...












Code

col

#10
I built and tested this with a standard BMax build that uses MingW9.3 - using the later versions have bug fixes and compatibility issues resolved 8)
however this code should work with all versions.

You can get this to work with the original BlitzMax by modifying the BRL thread sources in a similar way that NG modified them. I did have a quick go at doing it without modifying them but some of the required functions are 'local' (static) functions in the BRL source so it looks like you'd have to alter them anyway so why not do it properly.

The examples seem to work ok with threaded and single-thread builds - requires some thorough testing though so if you get spurious crashes then think of this first.
All I did was add in these functions:

bbThreadRegister
bbThreadUnregister




brl.mod -> blitz.mod ->blitz_thread.h


#ifndef BLITZ_THREAD_H
#define BLITZ_THREAD_H

#ifdef _WIN32

#include <windows.h>
typedef CRITICAL_SECTION bb_mutex_t;
#define bb_mutex_init(MUTPTR) (InitializeCriticalSection(MUTPTR),1)
#define bb_mutex_destroy(MUTPTR) DeleteCriticalSection(MUTPTR)
#define bb_mutex_lock(MUTPTR) EnterCriticalSection(MUTPTR)
#define bb_mutex_unlock(MUTPTR) LeaveCriticalSection(MUTPTR)
#define bb_mutex_trylock(MUTPTR) (TryEnterCriticalSection(MUTPTR)!=0)

/*
typedef HANDLE bb_mutex_t;
#define bb_mutex_init(MUTPTR) ((*(MUTPTR)=CreateMutex(0,0,0))!=0)
#define bb_mutex_destroy(MUTPTR) CloseHandle(*(MUTPTR))
#define bb_mutex_lock(MUTPTR) WaitForSingleObject(*(MUTPTR),INFINITE)
#define bb_mutex_unlock(MUTPTR) ReleaseMutex(*(MUTPTR))
#define bb_mutex_trylock(MUTPTR) (WaitForSingleObject(*(MUTPTR),0 )==WAIT_OBJECT_0)
*/

typedef HANDLE bb_sem_t;
#define bb_sem_init(SEMPTR,COUNT) ((*(SEMPTR)=CreateSemaphore(0,(COUNT),0x7fffffff,0))!=0)
#define bb_sem_destroy(SEMPTR) CloseHandle(*(SEMPTR))
#define bb_sem_wait(SEMPTR) WaitForSingleObject(*(SEMPTR),INFINITE)
#define bb_sem_post(SEMPTR) ReleaseSemaphore(*(SEMPTR),1,0)

#else

#include <pthread.h>
typedef pthread_mutex_t bb_mutex_t;
extern pthread_mutexattr_t _bb_mutexattr;
#define bb_mutex_init(MUTPTR) (pthread_mutex_init((MUTPTR),&_bb_mutexattr)>=0)
#define bb_mutex_destroy(MUTPTR) pthread_mutex_destroy(MUTPTR)
#define bb_mutex_lock(MUTPTR) pthread_mutex_lock(MUTPTR)
#define bb_mutex_unlock(MUTPTR) pthread_mutex_unlock(MUTPTR)
#define bb_mutex_trylock(MUTPTR) (pthread_mutex_trylock(MUTPTR)==0)

#endif

#ifdef __APPLE__

#include <mach/semaphore.h>
#include <mach/task.h>
typedef semaphore_t bb_sem_t;
#define bb_sem_init(SEMPTR,COUNT) (semaphore_create( mach_task_self(),(SEMPTR),SYNC_POLICY_FIFO,(COUNT) )>=0)
#define bb_sem_destroy(SEMPTR) semaphore_destroy( mach_task_self(),*(SEMPTR) )
#define bb_sem_wait(SEMPTR) semaphore_wait( *(SEMPTR) )
#define bb_sem_post(SEMPTR) semaphore_signal( *(SEMPTR) )

#endif

#ifdef __linux

#include <semaphore.h>
typedef sem_t bb_sem_t;
#define bb_sem_init(SEMPTR,COUNT) (sem_init((SEMPTR),0,(COUNT))>=0)
#define bb_sem_destroy sem_destroy
#define bb_sem_wait sem_wait
#define bb_sem_post sem_post

#endif

#ifdef _WIN32
#define BB_THREADREGS 7 //via GetThreadContext()
#elif __ppc__
#define BB_THREADREGS 19 //via bbGCRootRegs()
#else
#define BB_THREADREGS 4 //vid bbGCRootRegs()
#endif

#include "blitz_types.h"

typedef BBObject *(*BBThreadProc)( BBObject* );

typedef struct BBThread BBThread;

struct BBThread{
BBThread *succ;
BBThreadProc proc;
void *data[32];
int detached;
void *stackTop;
void *locked_sp;
int locked_regs[BB_THREADREGS];
#ifdef _WIN32
HANDLE handle;
DWORD id;
#else
pthread_t handle;
int suspended;
bb_sem_t runsema;
bb_sem_t acksema;
#endif
};

void bbThreadStartup();

BBThread* bbThreadCreate( BBThreadProc entry,BBObject *data );
void bbThreadDetach( BBThread *thread );
BBObject* bbThreadWait( BBThread *thread );

BBThread* bbThreadGetMain();
BBThread* bbThreadGetCurrent();

int bbThreadSuspend( BBThread *thread );
int bbThreadResume( BBThread *thread );

int bbThreadAllocData();
void bbThreadSetData( int index,BBObject *data );
BBObject* bbThreadGetData( int index );

//These MUST be inside a BB_LOCK/BB_UNLOCK
BBThread* _bbThreadLockThreads();
void _bbThreadUnlockThreads();

int bbAtomicCAS( volatile int *target,int oldVal,int newVal );
int bbAtomicAdd( volatile int *target,int incr );

// Expose bbThreadRegister and bbThreadUnregister
#ifdef WIN32
BBThread* bbThreadRegister(DWORD id);
#else
BBThread* bbThreadRegister(void* handle);
#endif
void bbThreadUnregister(BBThread* thread);

//Internal locks...
extern int _bbNeedsLock;
extern bb_mutex_t _bbLock;

#define BB_LOCK if( _bbNeedsLock ){ bb_mutex_lock( &_bbLock ); }
#define BB_UNLOCK if( _bbNeedsLock ){ bb_mutex_unlock( &_bbLock ); }

#endif




brl.mod -> blitz.mod ->blitz_thread.c


#include "blitz.h"

//#define DEBUG_THREADS

//***** Common *****

int _bbNeedsLock;
bb_mutex_t _bbLock;

static int threadDataId;

static BBThread *threads;
static BBThread *deadThreads;

static BBThread *mainThread;

static void flushDeadThreads(){
BBThread **p=&deadThreads,*t;
while( t=*p ){
if( t->detached ){
*p=t->succ;
#ifdef _WIN32
CloseHandle( t->handle );
#endif
free( t );
}else{
p=&t->succ;
}
}
}

static void addThread( BBThread *thread ){
flushDeadThreads();
thread->succ=threads;
threads=thread;
}

static void removeThread( BBThread *thread ){
BBThread **p=&threads,*t;
while( t=*p ){
if( t==thread ){
*p=t->succ;
if( t->detached ){
#ifdef _WIN32
CloseHandle( t->handle );
#endif
free( t );
}else{
t->succ=deadThreads;
deadThreads=t;
}
break;
}else{
p=&t->succ;
}
}
}

int bbThreadAllocData(){
if( threadDataId<31 ) return ++threadDataId;
return 0;
}

void bbThreadSetData( int index,BBObject *data ){
bbThreadGetCurrent()->data[index]=data;
}

BBObject *bbThreadGetData( int index ){
BBObject *data=bbThreadGetCurrent()->data[index];
return data ? data : &bbNullObject;
}

void bbThreadUnregister(BBThread* thread)
{
BB_LOCK
removeThread( thread );
BB_UNLOCK
}

//***** Windows threads *****
#ifdef _WIN32

static DWORD curThreadTls;

static DWORD WINAPI threadProc( void *p ){
BBThread *thread=p;

TlsSetValue( curThreadTls,thread );

DWORD ret=(DWORD)thread->proc( thread->data[0] );

BB_LOCK
removeThread( thread );
BB_UNLOCK

return ret;
}

void bbThreadStartup(){

if( bb_mutex_init( &_bbLock )<0 ) exit(-1);

curThreadTls=TlsAlloc();

BBThread *thread=malloc( sizeof( BBThread ) );

thread->proc=0;
memset( thread->data,0,sizeof(thread->data) );
thread->detached=0;
thread->stackTop=bbGCStackTop;
thread->id=GetCurrentThreadId();
if( !DuplicateHandle( GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&thread->handle,0,FALSE,DUPLICATE_SAME_ACCESS ) ){
exit( -1 );
}

TlsSetValue( curThreadTls,thread );

thread->succ=threads;
threads=thread;
mainThread=thread;
}

BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
BBThread *thread=malloc( sizeof( BBThread ) );

thread->proc=proc;
memset( thread->data,0,sizeof(thread->data) );
thread->data[0]=data;
thread->detached=0;
thread->handle=CreateThread( 0,0,threadProc,thread,CREATE_SUSPENDED,&thread->id );

CONTEXT ctx={CONTEXT_CONTROL};
GetThreadContext( thread->handle,&ctx );
thread->stackTop=ctx.Esp;

BB_LOCK
addThread( thread );
BB_UNLOCK

_bbNeedsLock=1;

return thread;
}

void bbThreadDetach( BBThread *thread ){
thread->detached=1;
}

BBObject *bbThreadWait( BBThread *thread ){
if( WaitForSingleObject( thread->handle,INFINITE )==WAIT_OBJECT_0 ){
BBObject *p;
if( GetExitCodeThread( thread->handle,(DWORD*)&p ) ){
thread->detached=1;
return p;
}else{
printf( "ERROR! bbThreadWait: GetExitCodeThread failed!\n" );
}
}else{
printf( "ERROR! bbThreadWait: WaitForSingleObject failed!\n" );
}
printf( "LastError=%i\n",GetLastError() );

return &bbNullObject;
}

BBThread *bbThreadGetMain(){
return mainThread;
}

BBThread *bbThreadGetCurrent(){
return TlsGetValue( curThreadTls );
}

int bbThreadSuspend( BBThread *thread ){
return SuspendThread( thread->handle );
}

int bbThreadResume( BBThread *thread ){
return ResumeThread( thread->handle );
}

BBThread *_bbThreadLockThreads(){
BBThread *curThread=bbThreadGetCurrent();
BBThread *t;
for( t=threads;t;t=t->succ ){
if( t!=curThread ){
SuspendThread( t->handle );
CONTEXT ctx={CONTEXT_INTEGER|CONTEXT_CONTROL};
GetThreadContext( t->handle,&ctx );
t->locked_regs[0]=ctx.Edi;
t->locked_regs[1]=ctx.Esi;
t->locked_regs[2]=ctx.Ebx;
t->locked_regs[3]=ctx.Edx;
t->locked_regs[4]=ctx.Ecx;
t->locked_regs[5]=ctx.Eax;
t->locked_regs[6]=ctx.Ebp;
t->locked_sp=ctx.Esp;
}
}
return threads;
}

void _bbThreadUnlockThreads(){
BBThread *curThread=bbThreadGetCurrent();
BBThread *t;
for( t=threads;t;t=t->succ ){
if( t!=curThread ){
ResumeThread( t->handle );
}
}
}

BBThread* bbThreadRegister(DWORD id)
{
BBThread* thread = 0;
HANDLE handle = OpenThread(THREAD_GET_CONTEXT , FALSE, id);
if(handle)
{
thread = malloc(sizeof(BBThread));
thread->proc = 0;
thread->data[0] = 0;
thread->detached = 0;
thread->id = id;

CONTEXT ctx={CONTEXT_CONTROL};
GetThreadContext( thread->handle,&ctx );
thread->stackTop=ctx.Esp;
CloseHandle(handle);

BB_LOCK
addThread( thread );
BB_UNLOCK

_bbNeedsLock = 1;
}
else
{
printf("WARNING: Thread with id: %d was not registered with the Blitz system.\n", id);
printf("         This will result in an unstable program - especially for Debug builds.\n");
fflush(0);
}

return thread;
}

//***** POSIX threads *****
#else

#include <unistd.h>
#include <signal.h>

#if __linux
#define MUTEX_RECURSIVE 1
#elif __APPLE__
#define MUTEX_RECURSIVE 2
#endif

pthread_mutexattr_t _bb_mutexattr;

static BBThread *threads;
static pthread_key_t curThreadTls;

static void suspendSigHandler( int sig ){//,siginfo_t *info,ucontext_t *ctx ){
BBThread *thread=pthread_getspecific( curThreadTls );

thread->locked_sp=bbGCRootRegs( thread->locked_regs );

#ifdef DEBUG_THREADS
printf( "In suspendSigHandler! thread=%p locked_sp=%p\n",thread,thread->locked_sp );fflush( stdout );
#endif

bb_sem_post( &thread->acksema );

//wait for resume - apparently very naughty!
bb_sem_wait( &thread->runsema );

#ifdef DEBUG_THREADS
printf( "Got resume!\n" );fflush( stdout );
#endif
}

void bbThreadStartup(){

if( pthread_mutexattr_init( &_bb_mutexattr )<0 ) exit(-1);
if( pthread_mutexattr_settype( &_bb_mutexattr,MUTEX_RECURSIVE )<0 ) exit(-1);

if( pthread_key_create( &curThreadTls,0 )<0 ) exit(-1);

if( bb_mutex_init( &_bbLock )<0 ) exit(-1);

struct sigaction act;
memset( &act,0,sizeof(act) );
act.sa_handler=suspendSigHandler;
act.sa_flags=SA_RESTART;

if( sigaction( SIGUSR2,&act,0 )<0 ) exit(-1);

BBThread *thread=malloc( sizeof( BBThread ) );
memset( thread->data,0,sizeof(thread->data) );

thread->proc=0;
thread->detached=0;
thread->suspended=0;
thread->handle=pthread_self();
if( !bb_sem_init( &thread->runsema,0 ) ) exit(-1);
if( !bb_sem_init( &thread->acksema,0 ) ) exit(-1);

thread->stackTop=bbGCStackTop;
pthread_setspecific( curThreadTls,thread );

thread->succ=threads;
threads=thread;
mainThread=thread;
}

static void *threadProc( void *p ){
BBThread *thread=p;

thread->stackTop=bbGCRootRegs( thread->locked_regs );
pthread_setspecific( curThreadTls,thread );

BB_LOCK
addThread( thread );
BB_UNLOCK

bb_sem_post( &thread->acksema );
bb_sem_wait( &thread->runsema );

#ifdef DEBUG_THREADS
printf( "Thread %p added, stackTop=%p\n",thread,thread->stackTop );fflush( stdout );
#endif

void *ret=thread->proc( thread->data[0] );

BB_LOCK
removeThread( thread );
BB_UNLOCK

bb_sem_destroy( &thread->runsema );
bb_sem_destroy( &thread->acksema );

#ifdef DEBUG_THREADS
printf( "Thread %p removed\n",thread );fflush( stdout );
#endif

return ret;
}

BBThread *bbThreadCreate( BBThreadProc proc,BBObject *data ){
BBThread *thread=malloc( sizeof( BBThread ) );
memset( thread->data,0,sizeof(thread->data) );

thread->proc=proc;
thread->data[0]=data;
thread->detached=0;
thread->suspended=1;
if( bb_sem_init( &thread->runsema,0 ) ){
if( bb_sem_init( &thread->acksema,0 ) ){
if( pthread_create( &thread->handle,0,threadProc,thread )>=0 ){
bb_sem_wait( &thread->acksema );
_bbNeedsLock=1;
return thread;
}
bb_sem_destroy( &thread->acksema );
}
bb_sem_destroy( &thread->runsema );
}
free( thread );
return 0;
}

void bbThreadDetach( BBThread *thread ){
thread->detached=1;
pthread_detach( thread->handle );
}

BBObject *bbThreadWait( BBThread *thread ){
BBObject *p=0;
thread->detached=1;
pthread_join( thread->handle,&p );
return p;
}

BBThread *bbThreadGetMain(){
return mainThread;
}

BBThread *bbThreadGetCurrent(){
return pthread_getspecific( curThreadTls );
}

int bbThreadSuspend( BBThread *thread ){
BB_LOCK

int n=thread->suspended++;

if( n==0 ){
pthread_kill( thread->handle,SIGUSR2 );
bb_sem_wait( &thread->acksema );
}

BB_UNLOCK

return n;
}

int bbThreadResume( BBThread *thread ){
BB_LOCK

int n=thread->suspended--;

if( n==1 ){
bb_sem_post( &thread->runsema );
}

BB_UNLOCK

return n;
}

BBThread *_bbThreadLockThreads(){
BBThread *curThread=bbThreadGetCurrent();
BBThread *t;
for( t=threads;t;t=t->succ ){
if( t!=curThread ){
if( !t->suspended++ ){
pthread_kill( t->handle,SIGUSR2 );
bb_sem_wait( &t->acksema );
}
}
}
return threads;
}

void _bbThreadUnlockThreads(){
BBThread *curThread=bbThreadGetCurrent();
BBThread *t;
for( t=threads;t;t=t->succ ){
if( t!=curThread ){
if( !--t->suspended ){
bb_sem_post( &t->runsema );
}
}
}
}}

BBThread* bbThreadRegister(void* handle)
{
BBThread* thread = malloc(sizeof(BBThread);
memset(thread->data, 0, sizeof(thread->data));

thread->handle = handle;
thread->proc = 0;
thread->data[0] = 0;
thread->detached = 0;
pthread_setspecific(curThreadTls, thread);

BB_LOCK
addThread(thread);
BB_UBLOCK;

_bbNeedsLock = 1;

return thread;
}

#endif

//***** Atomic ops *****
#if __ppc__

int bbAtomicCAS( volatile int *addr,int old,int new_val ){
int oldval;
int result=0;

__asm__ __volatile__(
"1:lwarx %0,0,%2\n"   /* load and reserve              */
"cmpw %0, %4\n"      /* if load is not equal to */
"bne 2f\n"            /*   old, fail */
"stwcx. %3,0,%2\n"    /* else store conditional         */
"bne- 1b\n"           /* retry if lost reservation      */
"li %1,1\n"      /* result = 1; */
"2:\n"
: "=&r"(oldval), "=&r"(result)
: "r"(addr), "r"(new_val), "r"(old), "1"(result)
: "memory", "cc");

return result;
}

int bbAtomicAdd( volatile int *p,int incr ){
int old;
for(;;){
old=*p;
if( bbAtomicCAS( p,old,old+incr ) ) return old;
}
}

#else

int bbAtomicCAS( volatile int *addr,int old,int new_val ){
char result;

__asm__ __volatile__(
"lock; cmpxchgl %3, %0; setz %1"
: "=m"(*addr), "=q"(result)
: "m"(*addr), "r" (new_val), "a"(old) : "memory");

return (int)result;
}

int bbAtomicAdd( volatile int *p,int incr ){
int result;

__asm__ __volatile__ ("lock; xaddl %0, %1" :
"=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
: "memory");

return result;
}

#endif


I'll keep an eye on the other 'wrapper' posts to what transpires there.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Hardcoal

Last Error trying to compile miniaudio is

►mima.miniaudio was scheduled to next iteration
D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:2:19: fatal error: blitz.h: No such file or directory
#include "blitz.h"
                   ^
compilation terminated.
Build Error: failed to compile D:/PORTABLE/BlitzMax/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c
►►►►mima.miniaudio was not built. See error information on latest attempt.
Code

Hardcoal

Ok. I was busy doing other stuff related to this app.. so this MOD issue is being postponed.

I encountered a new silly problem, is there a way to read if mouse is down besides the usual mousedown(1) command?

I need a general way to read whether mouse button is down..

thanks
Code

Midimaster

What do you mean? Inside MaxGui objects? or inside a simple Graphics(80,600)-window?
Can you descripe a situation where you need a new function, because the MouseDown() is not working as you would need?
...back from Egypt

Derron

check how mouse input is read in brl.system or sdl.mod/system.mod - they register for system events. You could do that too.


bye
Ron