SCPipe_osx/scpipe.mm

271 lines
4.7 KiB
Plaintext

// scpipe.cpp : Defines the entry point for the console application.
//
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#import <Cocoa/Cocoa.h>
#include "SCCore.h"
// #define LOG_EXCHANGE
enum
{
BUFFER_SIZE = 4096
};
static NSFileHandle *pipe_in = nil;
static NSFileHandle *pipe_out = nil;
void put_bytes( const void * out, uint32_t size )
{
@autoreleasepool {
NSError *error;
NSData *data = [NSData dataWithBytes:out length:size];
[pipe_out writeData:data error:&error];
}
}
void put_code( uint32_t code )
{
put_bytes( &code, sizeof(code) );
}
void get_bytes( void * in, uint32_t size )
{
NSUInteger bytesDone;
@autoreleasepool {
NSError *error = nil;
NSData *data = [pipe_in readDataUpToLength:size error:&error];
if(!data || error) {
memset( in, 0, size );
return;
}
bytesDone = [data length];
memcpy(in, [data bytes], bytesDone);
}
if(bytesDone < size) {
memset(((uint8_t *)in) + bytesDone, 0, size - bytesDone);
}
}
uint32_t get_code()
{
uint32_t code;
get_bytes( &code, sizeof(code) );
return code;
}
int main( int argc, const char * argv[] )
{
if ( argv == NULL || argc != 2 ) return 1;
unsigned code = 0;
SCCore * sampler = NULL;
uint32_t sample_rate = 44100;
std::vector<float> sample_buffer;
unsigned int samples_buffered = 0;
uint8_t* msgbuf = NULL;
size_t msgsize = 0;
pipe_in = [NSFileHandle fileHandleWithStandardInput];
pipe_out = [NSFileHandle fileHandleWithStandardOutput];
sampler = new SCCore;
if ( !sampler->Load( argv[ 1 ] ) )
{
code = 1;
goto exit;
}
if (sampler->TG_initialize(0) < 0)
{
code = 2;
goto exit;
}
sample_buffer.resize( BUFFER_SIZE * 4 );
put_code( 0 );
for (;;)
{
uint32_t command = get_code();
if ( !command ) break;
switch ( command )
{
case 1: // Set Sample Rate
{
uint32_t size = get_code();
if ( size != sizeof(sample_rate) )
{
code = 10;
goto exit;
}
sample_rate = get_code();
sampler->TG_activate(44100.0, 1024);
sampler->TG_setMaxBlockSize(256);
sampler->TG_setSampleRate((float)sample_rate);
sampler->TG_setSampleRate((float)sample_rate);
sampler->TG_setMaxBlockSize(BUFFER_SIZE);
put_code( 0 );
}
break;
case 2: // Send MIDI Event
{
uint32_t b = get_code();
sampler->TG_ShortMidiIn(b, 0);
put_code( 0 );
}
break;
case 3: // Send System Exclusive Event
{
uint32_t size = get_code();
if (size + 1 > msgsize)
{
msgsize = (size + 1024) & ~1023;
msgbuf = (uint8_t *) realloc(msgbuf, msgsize);
}
if (!msgbuf)
{
code = 3;
goto exit;
}
get_bytes( msgbuf, size );
if ( msgbuf[size-1] != 0xF7 )
msgbuf[size] = 0xF7;
sampler->TG_LongMidiIn( msgbuf, 0 );
put_code( 0 );
}
break;
case 4: // Render Samples
{
uint32_t count = get_code();
put_code( 0 );
while( count )
{
unsigned count_to_do = MIN(count, BUFFER_SIZE);
memset(&sample_buffer[0], 0, count_to_do * sizeof(float));
memset(&sample_buffer[BUFFER_SIZE], 0, count_to_do * sizeof(float));
sampler->TG_setInterruptThreadIdAtThisTime();
sampler->TG_Process(&sample_buffer[0], &sample_buffer[BUFFER_SIZE], count_to_do);
float * out = &sample_buffer[BUFFER_SIZE * 2];
for ( unsigned i = 0; i < count_to_do; ++i )
{
float sample = sample_buffer[i];
out[ 0 ] = sample;
sample = sample_buffer[BUFFER_SIZE + i];
out[ 1 ] = sample;
out += 2;
}
put_bytes( &sample_buffer[BUFFER_SIZE * 2], count_to_do * sizeof(float) * 2 );
count -= count_to_do;
}
}
break;
case 5: // Junk Samples
{
uint32_t count = get_code();
while ( count )
{
unsigned count_to_do = MIN(count, BUFFER_SIZE);
sampler->TG_setInterruptThreadIdAtThisTime();
sampler->TG_Process(&sample_buffer[0], &sample_buffer[BUFFER_SIZE], count_to_do);
count -= count_to_do;
}
put_code( 0 );
}
break;
case 6: // Send event, with timestamp
{
uint32_t b = get_code();
uint32_t timestamp = get_code();
sampler->TG_ShortMidiIn(b, timestamp);
put_code( 0 );
}
break;
case 7: // Send System Exclusive, with timestamp
{
uint32_t size = get_code();
uint32_t timestamp = get_code();
if (size + 1 > msgsize)
{
msgsize = (size + 1024) & ~1023;
msgbuf = (uint8_t*)realloc(msgbuf, msgsize);
}
if (!msgbuf)
{
code = 3;
goto exit;
}
get_bytes(msgbuf, size);
if (msgbuf[size - 1] != 0xF7)
msgbuf[size] = 0xF7;
sampler->TG_LongMidiIn(msgbuf, timestamp);
put_code(0);
}
break;
default:
code = 4;
goto exit;
break;
}
}
exit:
delete sampler;
put_code( code );
return code;
}