Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 064306a0df
Fetching contributors…

Cannot retrieve contributors at this time

586 lines (452 sloc) 17.14 kb
//-----------------------------------------------------------------------------
// Entaro ChucK Developer!
// This is a Chugin boilerplate, generated by chugerate!
//-----------------------------------------------------------------------------
// this should align with the correct versions of these ChucK files
#include "chuck_dl.h"
#include "chuck_def.h"
#include "chuck_oo.h"
#include "chuck_instr.h"
#include "chuck_type.h"
#include <AudioUnit/AudioUnit.h>
#include <AudioUnit/AudioUnitCarbonView.h>
#include <CoreAudio/CoreAudio.h>
#include <CoreAudioKit/CoreAudioKit.h>
#include <Foundation/Foundation.h>
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include "PublicUtility/CAComponent.h"
#include "PublicUtility/CABufferList.h"
#include "PublicUtility/CAComponentDescription.h"
#include "PublicUtility/CAStreamBasicDescription.h"
// general includes
#include <stdio.h>
#include <limits.h>
#include <map>
using namespace std;
// declaration of chugin constructor
CK_DLL_CTOR(audiounit_ctor);
// declaration of chugin desctructor
CK_DLL_DTOR(audiounit_dtor);
CK_DLL_SFUN(audiounit_list);
// for Chugins extending UGen, this is mono synthesis function for 1 sample
CK_DLL_TICKF(audiounit_tickf);
CK_DLL_MFUN(audiounit_open);
CK_DLL_MFUN(audiounit_send);
CK_DLL_MFUN(audiounit_display);
// this is a special offset reserved for Chugin internal data
t_CKINT audiounit_data_offset = 0;
class CKAudioUnitManager
{
public:
static CKAudioUnitManager * instance()
{
static CKAudioUnitManager * g_staticInstance = NULL;
if(!g_staticInstance)
{
g_staticInstance = new CKAudioUnitManager;
}
return g_staticInstance;
}
Chuck_Array * list()
{
load_components();
Chuck_Array4 * array = new Chuck_Array4(TRUE, m_names.size());
initialize_object(array, &t_array);
int i = 0;
for(map<string, CAComponentDescription>::iterator n = m_names.begin();
n != m_names.end(); n++, i++)
{
Chuck_String * str = new Chuck_String;
initialize_object(str, &t_string);
str->str = n->first;
array->set(i, (t_CKUINT) str);
}
return array;
}
AudioUnit open(const string &name)
{
AudioUnit au = NULL;
if(m_names.count(name))
{
CAComponent component(m_names[name]);
if(component.Open(au) != noErr)
return NULL;
}
return au;
}
protected:
CKAudioUnitManager()
{
m_loadedComponents = false;
}
void load_components()
{
if(m_loadedComponents)
return;
m_loadedComponents = true;
char buf[256];
//OSType type = kAudioUnitType_Effect;
OSType type = kAudioUnitType_MusicDevice;
CAComponentDescription desc = CAComponentDescription(type);
int count = desc.Count();
CAComponent ioComp;
for(int i = 0; i < count; i++)
{
ioComp = CAComponent(desc, &ioComp);
CFStringRef cfname = ioComp.GetAUName();
CFStringGetCString(cfname, buf, 256, kCFStringEncodingUTF8);
string name = string(buf);
m_names[name] = ioComp.Desc();
}
}
bool m_loadedComponents;
map<string, CAComponentDescription> m_names;
};
@interface CKAudioUnitHelper : NSObject
{
AudioUnit m_au;
NSWindow * m_window;
}
// call on any thread
- (id)initWithAudioUnit:(AudioUnit)au;
// only call on main thread
- (void)display;
@end
@implementation CKAudioUnitHelper
// call on any thread
- (id)initWithAudioUnit:(AudioUnit)au
{
if(self = [super init])
{
m_au = au;
m_window = nil;
}
return self;
}
// only call on main thread
- (void)display
{
if(m_window == nil)
{
// NSRect r = NSMakeRect(0, 0, 500, 500);
// m_window = [[NSWindow alloc] initWithContentRect:r
// styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask
// backing:NSBackingStoreBuffered
// defer:YES];
// [m_window setReleasedWhenClosed:NO];
//// [m_window setContentView:[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)] autorelease]];
// [m_window center];
}
#if !__LP64__
// WindowRef carbonWindow = (WindowRef) [m_window windowRef];
OSStatus result;
HIWindowRef carbonWindow;
Rect windowRect = { 0, 0, 500, 500 };
result = CreateNewWindow(kDocumentWindowClass,
kWindowStandardHandlerAttribute |
kWindowCloseBoxAttribute |
kWindowCollapseBoxAttribute |
kWindowCompositingAttribute,
&windowRect, &carbonWindow);
CreateRootControl(carbonWindow, NULL);
ControlRef rootControl = NULL;
GetRootControl(carbonWindow, &rootControl);
UInt32 dataSize;
Boolean isWritable;
AudioComponentDescription * carbonViewDescs = NULL;
UInt32 numComponents;
result = AudioUnitGetPropertyInfo(m_au,
kAudioUnitProperty_GetUIComponentList,
kAudioUnitScope_Global,
0,
&dataSize,
&isWritable );
numComponents = dataSize/sizeof(AudioComponentDescription);
carbonViewDescs = new AudioComponentDescription[numComponents];
result = AudioUnitGetProperty(m_au,
kAudioUnitProperty_GetUIComponentList,
kAudioUnitScope_Global,
0,
carbonViewDescs,
&dataSize);
AudioComponent uiComponent = AudioComponentFindNext(NULL, &carbonViewDescs[0]);
AudioComponentInstance uiComponentInstance;
AudioComponentInstanceNew(uiComponent, &uiComponentInstance);
ControlRef auControl;
Float32Point auLoc = { 0, 0 };
Float32Point auSize = { 500, 500 };
result = AudioUnitCarbonViewCreate(uiComponentInstance, m_au, carbonWindow, rootControl,
&auLoc, &auSize, &auControl);
Rect controlRect;
GetControlBounds(auControl, &controlRect);
SizeWindow(carbonWindow, controlRect.right - controlRect.left,
controlRect.bottom - controlRect.top, true);
// ActivateControl(auControl);
// EnableControl(auControl);
// ActivateWindow(carbonWindow, true);
// BringToFront(carbonWindow);
m_window = [[NSWindow alloc] initWithWindowRef:carbonWindow];
// Rect controlRect;
// GetControlBounds(auControl, &controlRect);
// [m_window setFrame:[m_window frameRectForContentRect:NSMakeRect(0, 0,
// controlRect.right - controlRect.left,
// controlRect.bottom - controlRect.top)]
// display:YES];
#endif
[m_window center];
[m_window makeKeyAndOrderFront:nil];
[m_window display];
}
@end
// class definition for internal Chugin data
// (note: this isn't strictly necessary, but serves as example
// of one recommended approach)
class CKAudioUnit
{
public:
// constructor
CKAudioUnit(t_CKFLOAT fs)
{
m_fs = fs;
m_timestamp.mSampleTime = 0;
m_timestamp.mFlags = kAudioTimeStampSampleTimeValid;
m_au = NULL;
m_buffer = NULL;
m_renderBufferSize = 64;
m_bufferPos = 0;
}
~CKAudioUnit()
{
close();
}
// for Chugins extending UGen
t_CKBOOL tick( SAMPLE * in, SAMPLE * out, t_CKUINT nframes )
{
if(!m_au)
return TRUE;
if(m_renderBufferSize == 0)
{
OSStatus result = AudioUnitRender(m_au, NULL, &m_timestamp, 0,
nframes,
&m_buffer->GetModifiableBufferList());
const Float32 * left = (Float32 *) m_buffer->GetBufferList().mBuffers[0].mData;
const Float32 * right = (Float32 *) m_buffer->GetBufferList().mBuffers[1].mData;
for(int i = 0; i < nframes; i++)
{
out[i*2] = left[i];
out[i*2+1] = right[i];
}
}
else
{
const Float32 * left = (Float32 *) m_buffer->GetBufferList().mBuffers[0].mData;
const Float32 * right = (Float32 *) m_buffer->GetBufferList().mBuffers[1].mData;
int frameNum = 0;
int framesAvailable = m_buffer->GetBufferList().mBuffers[0].mDataByteSize/sizeof(Float32) - m_bufferPos;
int framesToCopy = MIN(nframes, framesAvailable);
for(; frameNum < framesToCopy; frameNum++)
{
out[frameNum*2] = left[m_bufferPos + frameNum];
out[frameNum*2+1] = right[m_bufferPos + frameNum];
}
m_bufferPos += framesToCopy;
while(frameNum < nframes)
{
OSStatus result = AudioUnitRender(m_au, NULL, &m_timestamp, 0,
m_renderBufferSize,
&m_buffer->GetModifiableBufferList());
m_bufferPos = 0;
left = (Float32 *) m_buffer->GetBufferList().mBuffers[0].mData;
right = (Float32 *) m_buffer->GetBufferList().mBuffers[1].mData;
framesToCopy = MIN(nframes-frameNum, m_renderBufferSize);
for(int i = 0; i < framesToCopy; i++)
{
out[frameNum+i*2] = left[i];
out[frameNum+i*2+1] = right[i];
}
frameNum += framesToCopy;
m_bufferPos += framesToCopy;
}
}
m_timestamp.mSampleTime += nframes;
return TRUE;
}
t_CKBOOL open( const std::string &name )
{
// TODO: close if already open
AudioUnit au = CKAudioUnitManager::instance()->open(name);
if(au)
{
OSStatus result;
// UInt32 format_size = sizeof(format);
//
// result = AudioUnitGetProperty(au, kAudioUnitProperty_StreamFormat,
// kAudioUnitScope_Output, 0,
// &format, &format_size);
m_format.mFormatID = kAudioFormatLinearPCM;
m_format.mSampleRate = m_fs;
m_format.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
m_format.mChannelsPerFrame = 2;
m_format.mBitsPerChannel = 32;
m_format.mFramesPerPacket = 1;
m_format.mBytesPerFrame = 4;
m_format.mBytesPerPacket = 4;
// set stream property
result = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0,
&m_format, sizeof(m_format));
if(result != noErr)
goto error;
AudioUnitInitialize(au);
m_buffer = CABufferList::New(m_format);
m_au = au;
}
return TRUE;
error:
if(au)
AudioComponentInstanceDispose(au);
if(m_buffer)
{
delete m_buffer;
m_buffer = NULL;
}
return FALSE;
}
t_CKBOOL close()
{
if(m_au)
{
AudioUnitUninitialize(m_au);
AudioComponentInstanceDispose(m_au);
m_au = NULL;
}
if(m_buffer)
{
delete m_buffer;
m_buffer = NULL;
}
return TRUE;
}
t_CKBOOL send_midi(t_CKUINT data1, t_CKUINT data2, t_CKUINT data3)
{
if(!m_au)
return FALSE;
OSStatus result = MusicDeviceMIDIEvent(m_au, data1, data2, data3, 0);
if(result == noErr)
return TRUE;
else
return FALSE;
}
t_CKBOOL display()
{
CKAudioUnitHelper * helper = [[CKAudioUnitHelper alloc] initWithAudioUnit:m_au];
[helper performSelectorOnMainThread:@selector(display)
withObject:nil
waitUntilDone:NO];
return TRUE;
}
private:
float m_fs;
AudioUnit m_au;
AudioTimeStamp m_timestamp;
AudioStreamBasicDescription m_format;
t_CKUINT m_renderBufferSize;
t_CKUINT m_bufferPos;
CABufferList * m_buffer;
};
// query function: chuck calls this when loading the Chugin
// NOTE: developer will need to modify this function to
// add additional functions to this Chugin
CK_DLL_QUERY( AudioUnit )
{
// hmm, don't change this...
QUERY->setname(QUERY, "AudioUnit");
// begin the class definition
// can change the second argument to extend a different ChucK class
QUERY->begin_class(QUERY, "AudioUnit", "UGen");
// register the constructor (probably no need to change)
QUERY->add_ctor(QUERY, audiounit_ctor);
// register the destructor (probably no need to change)
QUERY->add_dtor(QUERY, audiounit_dtor);
// for UGen's only: add tick function
QUERY->add_ugen_funcf(QUERY, audiounit_tickf, NULL, 2, 2);
// NOTE: if this is to be a UGen with more than 1 channel,
// e.g., a multichannel UGen -- will need to use add_ugen_funcf()
// and declare a tickf function using CK_DLL_TICKF
QUERY->add_sfun(QUERY, audiounit_list, "string[]", "list");
QUERY->add_mfun(QUERY, audiounit_open, "int", "open");
QUERY->add_arg(QUERY, "string", "name");
QUERY->add_mfun(QUERY, audiounit_send, "int", "send");
QUERY->add_arg(QUERY, "int", "data1");
QUERY->add_arg(QUERY, "int", "data2");
QUERY->add_arg(QUERY, "int", "data3");
QUERY->add_mfun(QUERY, audiounit_display, "void", "display");
// this reserves a variable in the ChucK internal class to store
// referene to the c++ class we defined above
audiounit_data_offset = QUERY->add_mvar(QUERY, "int", "@au_data", false);
// end the class definition
// IMPORTANT: this MUST be called!
QUERY->end_class(QUERY);
// wasn't that a breeze?
return TRUE;
}
// implementation for the constructor
CK_DLL_CTOR(audiounit_ctor)
{
// get the offset where we'll store our internal c++ class pointer
OBJ_MEMBER_INT(SELF, audiounit_data_offset) = 0;
// instantiate our internal c++ class representation
CKAudioUnit * bcdata = new CKAudioUnit(API->vm->get_srate());
// store the pointer in the ChucK object member
OBJ_MEMBER_INT(SELF, audiounit_data_offset) = (t_CKINT) bcdata;
}
// implementation for the destructor
CK_DLL_DTOR(audiounit_dtor)
{
// get our c++ class pointer
CKAudioUnit * bcdata = (CKAudioUnit *) OBJ_MEMBER_INT(SELF, audiounit_data_offset);
// check it
if( bcdata )
{
// clean up
delete bcdata;
OBJ_MEMBER_INT(SELF, audiounit_data_offset) = 0;
bcdata = NULL;
}
}
// implementation for tick function
CK_DLL_TICKF(audiounit_tickf)
{
// get our c++ class pointer
CKAudioUnit * c = (CKAudioUnit *) OBJ_MEMBER_INT(SELF, audiounit_data_offset);
// invoke our tick function; store in the magical out variable
if(c) c->tick(in, out, nframes);
// yes
return TRUE;
}
// example implementation for setter
CK_DLL_SFUN(audiounit_list)
{
RETURN->v_object = CKAudioUnitManager::instance()->list();
}
CK_DLL_MFUN(audiounit_open)
{
// get our c++ class pointer
CKAudioUnit * c = (CKAudioUnit *) OBJ_MEMBER_INT(SELF, audiounit_data_offset);
RETURN->v_int = c->open(GET_NEXT_STRING(ARGS)->str);
}
CK_DLL_MFUN(audiounit_send)
{
// get our c++ class pointer
CKAudioUnit * c = (CKAudioUnit *) OBJ_MEMBER_INT(SELF, audiounit_data_offset);
t_CKINT data1 = GET_NEXT_INT(ARGS);
t_CKINT data2 = GET_NEXT_INT(ARGS);
t_CKINT data3 = GET_NEXT_INT(ARGS);
RETURN->v_int = c->send_midi(data1, data2, data3);
}
CK_DLL_MFUN(audiounit_display)
{
CKAudioUnit * c = (CKAudioUnit *) OBJ_MEMBER_INT(SELF, audiounit_data_offset);
c->display();
}
Jump to Line
Something went wrong with that request. Please try again.