271 lines
4.7 KiB
Plaintext
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;
|
|
}
|