Logo Search packages:      
Sourcecode: csound version File versions

MyDocument.m

//
//  MyDocument.m
//  CsoundX
//
//  Created by matt on 12/25/05.
//  Copyright 2005 Matt Ingalls

/*
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <unistd.h>
                   
#import "MyDocument.h"

#define TEXT_BUFFER_SIZE 32768

AudioBufferList *thisBuff;
MyDocument *gPlayingDocs = NULL;
float gInputBuffer;

@implementation MyDocument

- (id)init
{
    self = [super init];
    if (self) {
    
        // Add your subclass-specific initialization here.
        // If an error occurs here, send a [self release] message and return nil.
            
            mIsRealtime = YES; 
            mIsDone = 0;
            mTextBuffer = (char *)calloc(TEXT_BUFFER_SIZE, 1);
            mTextWriteIndex = 0;
            mTextReadIndex = 0;
//          mValues = 0;
    }
    return self;
}

- (void) dealloc 
{
      free(mTextBuffer);
      [super dealloc];
}

- (NSString *)windowNibName
{
    // Override returning the nib file name of the document
    // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
    return @"MyDocument";
}

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    // Add any code here that needs to be executed once the windowController has loaded the document's window.

      [textview insertText:[NSString stringWithContentsOfFile:[self fileName]]];
}

- (NSData *)dataRepresentationOfType:(NSString *)aType
{
    // Insert code here to write your document from the given data.  You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
    
    // For applications targeted for Tiger or later systems, you should use the new Tiger API -dataOfType:error:.  In this case you can also choose to override -writeToURL:ofType:error:, -fileWrapperOfType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.

    return nil;
}

- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
    // Insert code here to read your document from the given data.  You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead.
    
    // For applications targeted for Tiger or later systems, you should use the new Tiger API readFromData:ofType:error:.  In this case you can also choose to override -readFromURL:ofType:error: or -readFromFileWrapper:ofType:error: instead.
    
    return YES;
}

- (void)displayText:(NSString *)text
{
      [textview insertText:text];
}
            
- (void)writeText:(char *)str
{
      int len = strlen(str);
      // copy to our circular buffer
      if (len > 0) {
            while (len--)
            {
                  mTextBuffer = *str++;
                  if (mTextWriteIndex == TEXT_BUFFER_SIZE)
                        mTextWriteIndex = 0;
                  if (mTextWriteIndex == mTextReadIndex)
                        strcpy(mTextBuffer, "WARNING: TEXT BUFFER OVERFLOW");
            }
      }
      
      if (!mIsRealtime) // update now!
            [ self updateText ];
}


- (void)updateText
{
      char str;
      long writeIndex = mTextWriteIndex;
      long count = 0;
      while (mTextReadIndex != writeIndex && count < 32767)
      {
            str = mTextBuffer;
            if (mTextReadIndex == TEXT_BUFFER_SIZE)
                  mTextReadIndex = 0;
      }
      
      if (count)
      {
            [self displayText:[NSString stringWithCString:str length:count]];
      }
}

- (IBAction)stop:(id)sender
{
      mQuitRequested = true;
}

- (IBAction)rendertype:(id)sender
{
      mIsRealtime = !mIsRealtime;
}

- (IBAction)invalue:(id)sender
{
      NSControl *cntl = (NSControl *)sender;
      if (csound) {
            int channel = [ cntl tag ];
            mValues = [cntl floatValue];
      }
}

- (float)value:(int)channel
{
      if (channel >= 0 && channel < 128)
            return mValues;
      else
            return 0;
}

- (IBAction)render:(id)sender
{
      // load the lib
      csound = csoundCreate(self);
                        
      // setup our callbacks
      csoundSetMessageCallback(csound, CS_StandardOutput);

      int err = csoundPreCompile(csound);
      
      // make sure the Lib is not using a newer version of the api we do not know about
      if (err || csoundGetAPIVersion() != 100) {
            [self displayText:[NSString stringWithCString:"ERROR: CsoundLib not compatible with this version\n"]];
            return;
      }
      
      csoundSetIsGraphable(csound, YES);
      csoundSetYieldCallback(csound, CS_Yield);
      csoundSetPlayopenCallback(csound, CS_Playopen);
      csoundSetRtplayCallback(csound, CS_Rtplay);
      csoundSetRecopenCallback(csound, CS_Recopen);
      csoundSetRtrecordCallback(csound, CS_Rtrecord);
      csoundSetRtcloseCallback(csound, CS_Rtclose);
      csoundSetInputValueCallback(csound, CS_GetValue);
      
      csoundSetGlobalEnv("OPCODEDIR", "/Library/Frameworks/CsoundLib.Framework/Versions/5.1/Resources/Opcodes/");
      csoundSetGlobalEnv("SFDIR", "/Users/matt/Documents/");

      // now run it!
      //  we run it in another thread here so that the window can update itself 
      //    in the main thread everytime we write our output to it
      //    it also demostrates calling the Peform() routines in the API

      mQuitRequested = false;
      [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:NULL];
}

- (void)run:(id)anObject
{
      // new thread requires an autorelease pool
      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

      // start a spinning progress bar just for looks
      [spinner startAnimation:self];      

      // now add all our commandline flags
      char *argv;
      long argc = 0;
      int i;
            
      argv = (char *)calloc(8, 1);
      strcpy(argv[argc++], "csound");
      
      char *filePath = (char *)[[self fileName] cString]; 
      argv = (char *)calloc((strlen(filePath)/8+1)*8, 1);
      strcpy(argv[argc++], filePath);
      
      if (0 != strstr(filePath, ".orc")) {
            argv = (char *)calloc((strlen(filePath)/8+1)*8, 1);
            strncat(argv[argc], filePath, strlen(filePath)-3);
            strcat(argv[argc++], "sco");
      }
      
      if (0 != strstr(filePath, ".sco")) {
            argv = (char *)calloc((strlen(filePath)/8+1)*8, 1);
            strncat(argv[argc], filePath, strlen(filePath)-3);
            strcat(argv[argc++], "orc");
      }
      
      argv = (char *)calloc(8, 1);
      strcpy(argv[argc++], "-A");
      
      if (mIsRealtime) {
            argv = (char *)calloc(8, 1);
            strcat(argv[argc++], "-odac");
            
            argv = (char *)calloc(8, 1);
            strcat(argv[argc++], "-iadc");
            
            argv = (char *)malloc(strlen("-+rtaudio=null"));
            strcpy(argv[argc++], "-+rtaudio=null");
            
            argv = (char *)calloc(8, 1);
            sprintf(argv[argc++], "-b%d", RT_BUFFERSIZE);
            
            argv = (char *)calloc(8, 1);
            strcpy(argv[argc++], "-f");
            
            argv = (char *)calloc(8, 1);
            strcpy(argv[argc++], "-M0");
      }
      else {
            argv = (char *)calloc(((strlen(filePath)+2)/8+1)*8, 1);
            strcpy(argv[argc], "-o");
            strncat(argv[argc], filePath, strlen(filePath)-3);
            strcat(argv[argc++], "aif");
      
            argv = (char *)calloc(8, 1);
            strcpy(argv[argc++], "-3");
            
            argv = (char *)calloc(8, 1);
            strcpy(argv[argc++], "-R");
      
            argv = (char *)calloc(8, 1);
            strcpy(argv[argc++], "-b32768");
      }

      // Compile() loads the .csd and gets everything ready to run
      mIsDone = csoundCompile(csound, argc, argv);    
      [ self updateText ];
      
      if (!mIsDone) {
            if (!mIsRealtime)
                  mIsDone = csoundPerform(csound);
            else {
                  [ self addToPlaylist ];
                  while (!mIsDone) {
                        usleep(10000);
                        [ self updateText ];
                  }
            }           
            
            // always need to call destroy to cleanup, remove temp files and other stuff
            csoundDestroy(csound);
      }
      
      [ self updateText ];
      csound = NULL;
      
      for (i = 0; i < argc; i++)
            free(argv[i]);
            
      // finally, cleanup things in this thread
      [spinner stopAnimation:self];
      [pool release];
}

- (void)addToPlaylist
{
      mNextPlaying = gPlayingDocs;
      gPlayingDocs = self;
}

- (void)removeFromPlaylist
{
      if (gPlayingDocs == self) {
            gPlayingDocs = mNextPlaying;
            mNextPlaying = NULL;
            return;
      }
      
      MyDocument *doc = gPlayingDocs;
      while (doc) {
            if (doc->mNextPlaying == self) {
                  doc->mNextPlaying = mNextPlaying;
                  mNextPlaying = NULL;
                  return;
            }
            
            doc = doc->mNextPlaying;
      }
      
      // shouldn't get here, but just in case:
      mNextPlaying = NULL;
}

- (int)processAudio:(AudioBufferList *)ioData;
{
      if (csound && mIsRealtime && !mIsDone) {
            thisBuff = ioData;
            mIsDone = csoundPerformBuffer(csound);    
      }
      
      return mIsDone;
}


@end

// this function is called by csound when it outputs text messages
// currently the MacOSX csoundlib always outputs a cstring with no args,
// so you can ignore the va_list
void CS_StandardOutput(CSOUND *cs, int attr, const char *format, va_list args)
{
//    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

      MyDocument* obj = (MyDocument *)csoundGetHostData(cs);
      if (obj)
      {     
            char str;
            vsprintf(str, format, args);
            [obj writeText:str];
      }
      
//    [pool release];
}

// this function is called by csound, on some platforms, it means it is time
// to update GUI things, etc.. but here we really only need to use it to
// tell csound if we want to keep going.  if we return false, csound will
// gracefully terminate
int CS_Yield(CSOUND *cs)
{     
      MyDocument* obj = (MyDocument*)csoundGetHostData(cs);
      if (obj)
      {
            return !obj->mQuitRequested;
      }
      
      return 0;
}

int CS_Playopen(CSOUND *cs, const csRtAudioParams *parm)
{
      return 0;
}
void CS_Rtplay(CSOUND *cs, const MYFLT *outBuf, int nbytes)
{
      MyDocument* obj = (MyDocument*)csoundGetHostData(cs);
      if (obj) {
            int nchnls = obj->mRTParams.nChannels;
            for (int frame = 0; frame < nbytes/(sizeof(MYFLT)*nchnls); frame++) {
                  for (int chan = 0; chan < thisBuff->mNumberBuffers; chan++) {
                        ((MYFLT *)thisBuff->mBuffers[chan].mData) += *outBuf;
                        if (chan < nchnls-1)
                              outBuf++;
                  }
                  outBuf++;
            }
      }
}

int CS_Recopen(CSOUND *cs, const csRtAudioParams *parm)
{
      MyDocument* obj = (MyDocument*)csoundGetHostData(cs);
      if (obj)
            obj->mRTParams = *parm;
            
      return 0;
}
int CS_Rtrecord(CSOUND *cs,  MYFLT *inBuf, int nbytes)
{
      memcpy(inBuf, gInputBuffer, nbytes);
      return nbytes;
}
void CS_Rtclose(CSOUND *cs)
{
}
void CS_GetValue(CSOUND *cs, const char *channelName, float *value)
{
      MyDocument* obj = (MyDocument*)csoundGetHostData(cs);
      if (obj)
            *value = [ obj value:atoi(channelName) ];
      else
            *value = 0;
}

void Process(AudioBufferList * ioData)
{
      // copy our input and initialize buffer
      float *buf = gInputBuffer;
      for (int frame = 0; frame < ioData->mBuffers.mDataByteSize/sizeof(float); frame++)
            for (int chan = 0; chan < ioData->mNumberBuffers; chan++) {
                  *buf++ = ((MYFLT *)ioData->mBuffers[chan].mData)[frame];
                  ((MYFLT *)ioData->mBuffers[chan].mData) = 0;
            }
                  
      // now process
      MyDocument *docs = gPlayingDocs;
      while (docs) {
            int isDone = [ docs processAudio:ioData ];
            if (isDone) {
                  MyDocument *toRemove = docs;
                  docs = docs->mNextPlaying;
                  [ toRemove removeFromPlaylist];
            }
            else
                  docs = docs->mNextPlaying;
      }
}

Generated by  Doxygen 1.6.0   Back to index