| @@ -34,9 +34,20 @@ bool Pawfal_YesNo(const char *a,...) | |||
| ::vsnprintf(buffer, 1024, a, ap); | |||
| } | |||
| va_end(ap); | |||
| #if !__APPLE__ | |||
| PawfalYesNo pi(300, 100,buffer); | |||
| if (pi.go()) return true; | |||
| #else | |||
| Str255 copy; | |||
| strncpy((char*)copy + 1, buffer, 253); | |||
| copy[0] = strlen((char*)copy+1); | |||
| AlertStdAlertParamRec rec = { true, false, NULL, | |||
| (StringPtr)-1, (StringPtr)-1, NULL, | |||
| kAlertStdAlertOKButton, 0, kWindowAlertPositionParentWindowScreen }; | |||
| SInt16 ret = 0; | |||
| StandardAlert(kAlertCautionAlert, copy, NULL, &rec, &ret); | |||
| return ret == kAlertStdAlertOKButton; | |||
| #endif | |||
| return false; | |||
| } | |||
| @@ -45,6 +45,10 @@ static int NKEYS = 30; | |||
| MidiDevice *MidiDevice::m_Singleton; | |||
| string MidiDevice::m_DeviceName; | |||
| #if __APPLE__ | |||
| #define read AppleRead | |||
| #endif | |||
| MidiDevice::MidiDevice() : | |||
| m_Poly(1) | |||
| { | |||
| @@ -52,9 +56,7 @@ m_Poly(1) | |||
| seq_handle=AlsaOpen(); | |||
| #else | |||
| Open(); | |||
| #endif | |||
| #endif | |||
| #ifdef KEYBOARD_SUPPORT | |||
| m_Oct=4; | |||
| @@ -78,6 +80,9 @@ MidiDevice::~MidiDevice() | |||
| void MidiDevice::Close() | |||
| { | |||
| #if __APPLE__ | |||
| AppleClose(); | |||
| #else | |||
| pthread_mutex_lock(m_Mutex); | |||
| pthread_cancel(m_MidiReader); | |||
| pthread_mutex_unlock(m_Mutex); | |||
| @@ -86,11 +91,15 @@ void MidiDevice::Close() | |||
| close(m_MidiFd); | |||
| close(m_MidiWrFd); | |||
| cerr<<"Closed midi device"<<endl; | |||
| #endif // !__APPLE__ | |||
| } | |||
| void MidiDevice::Open() | |||
| { | |||
| #if __APPLE__ | |||
| AppleOpen(); | |||
| #else | |||
| //if (!SpiralInfo::WANTMIDI) return; | |||
| m_MidiFd = open(m_DeviceName.c_str(),O_RDONLY|O_SYNC); | |||
| @@ -108,6 +117,7 @@ void MidiDevice::Open() | |||
| } | |||
| cerr<<"Opened midi device ["<<m_DeviceName<<"]"<<endl; | |||
| #endif // !__APPLE__ | |||
| m_Mutex = new pthread_mutex_t; | |||
| pthread_mutex_init(m_Mutex, NULL); | |||
| @@ -402,3 +412,89 @@ snd_seq_t *MidiDevice::AlsaOpen() | |||
| #endif | |||
| #if __APPLE__ | |||
| void MidiDevice::AppleOpen() | |||
| { | |||
| m_ReadFillIndex = m_ReadReadIndex = 0; | |||
| OSStatus err = 0; | |||
| mMIDISource = NULL; | |||
| mMIDIClient = NULL; | |||
| mMIDIDestination = NULL; | |||
| err = MIDIClientCreate(CFSTR("org.pawpal.ssm"), NULL, NULL, &mMIDIClient); | |||
| if (err) printf("MIDIClientCreate failed returned %d\n", err); | |||
| if (!err) { | |||
| err = MIDISourceCreate(mMIDIClient, CFSTR("SpiralSynth"), &mMIDISource); | |||
| if (err) printf("MIDIInputPortCreate failed returned %d\n", err); | |||
| } | |||
| if (!err) { | |||
| err = MIDIDestinationCreate(mMIDIClient, CFSTR("SpiralSynth"), sMIDIRead, this, &mMIDIDestination); | |||
| MIDIObjectSetIntegerProperty(mMIDIDestination, kMIDIPropertyUniqueID, 'SSmP'); | |||
| } | |||
| } | |||
| void MidiDevice::AppleClose() | |||
| { | |||
| if (mMIDIDestination) | |||
| MIDIEndpointDispose(mMIDIDestination); | |||
| if (mMIDISource) | |||
| MIDIEndpointDispose(mMIDISource); | |||
| mMIDISource = NULL; | |||
| if (mMIDIClient) | |||
| MIDIClientDispose(mMIDIClient); | |||
| mMIDIClient = NULL; | |||
| } | |||
| int MidiDevice::AppleWrite(int dummy, unsigned char *outbuffer, int maxlen) | |||
| { | |||
| return 0; | |||
| } | |||
| int MidiDevice::AppleRead(int dummy, unsigned char *outbuffer, int maxlen) | |||
| { | |||
| if (!mMIDIClient) | |||
| return -1; | |||
| int len = 0; | |||
| do { | |||
| while (m_ReadReadIndex == m_ReadFillIndex) | |||
| usleep(1000); // 1ms | |||
| int readl = m_ReadFillIndex - m_ReadReadIndex; | |||
| if (readl < 0) | |||
| readl += midi_ReadSize; // wrapped | |||
| while (len < maxlen && readl-- > 0) { | |||
| int r = m_ReadReadIndex; | |||
| outbuffer[len++] = m_ReadBuffer[r]; | |||
| r++; | |||
| m_ReadReadIndex = r % midi_ReadSize; | |||
| } | |||
| } while (len < maxlen); | |||
| return len; | |||
| } | |||
| void MidiDevice::sMIDIRead(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon) | |||
| { | |||
| MidiDevice & t = *((MidiDevice*)readProcRefCon); | |||
| const MIDIPacket *packet = &pktlist->packet[0]; | |||
| for (int i = 0; i < (int)pktlist->numPackets; i++) { | |||
| const MIDIPacket & p = *packet; | |||
| for (int b = 0; b < p.length; b++) { | |||
| // printf("%02x ", p.data[b]); | |||
| int d = t.m_ReadFillIndex; | |||
| t.m_ReadBuffer[d] = p.data[b]; | |||
| d++; | |||
| t.m_ReadFillIndex = d % midi_ReadSize; | |||
| } | |||
| // printf("\n"); | |||
| packet = MIDIPacketNext(packet); | |||
| } | |||
| } | |||
| #endif | |||
| @@ -36,6 +36,10 @@ using namespace std; | |||
| #include <alsa/asoundlib.h> | |||
| #endif | |||
| #if __APPLE__ | |||
| #include <CoreMIDI/MIDIServices.h> | |||
| #endif | |||
| class MidiEvent | |||
| { | |||
| public: | |||
| @@ -97,6 +101,25 @@ private: | |||
| snd_seq_t *seq_handle; | |||
| snd_seq_t *AlsaOpen(); | |||
| #endif | |||
| #if __APPLE__ | |||
| MIDIClientRef mMIDIClient; | |||
| MIDIEndpointRef mMIDISource; | |||
| MIDIEndpointRef mMIDIDestination; | |||
| #define midi_ReadSize 4096 | |||
| unsigned char m_ReadBuffer[midi_ReadSize]; | |||
| volatile int m_ReadFillIndex; | |||
| volatile int m_ReadReadIndex; | |||
| void MidiDevice::AppleOpen(); | |||
| void MidiDevice::AppleClose(); | |||
| int MidiDevice::AppleWrite(int dummy, unsigned char *outbuffer, int maxlen); | |||
| int MidiDevice::AppleRead(int dummy, unsigned char *outbuffer, int maxlen); | |||
| static void MidiDevice::sMIDIRead(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon); | |||
| #endif | |||
| }; | |||
| #endif | |||
| @@ -35,7 +35,8 @@ class LFOPlugin : public SpiralPlugin { | |||
| virtual void StreamOut (ostream &s); | |||
| virtual void StreamIn (istream &s); | |||
| enum Type {SINE, TRIANGLE, SQUARE, SAW}; | |||
| typedef char Type; | |||
| enum {SINE, TRIANGLE, SQUARE, SAW}; | |||
| void WriteWaves(); | |||
| void NoteTrigger (int V, int s, int v); | |||
| @@ -34,7 +34,8 @@ public: | |||
| virtual void StreamOut(ostream &s); | |||
| virtual void StreamIn(istream &s); | |||
| enum Type{NONE,SQUARE,SAW,NOISE}; | |||
| typedef char Type; | |||
| enum {NONE,SQUARE,SAW,NOISE}; | |||
| void ModulateFreq(Sample *data) {m_FreqModBuf=data;} | |||
| void ModulatePulseWidth(Sample *data) {m_PulseWidthModBuf=data;} | |||
| @@ -186,8 +186,10 @@ void Fl_Loop::DrawPosMarker() | |||
| if (m_Pos) | |||
| { | |||
| float Angle=(*m_Pos/m_Length)*360.0; | |||
| fl_line_style(FL_SOLID, 3, NULL); | |||
| fl_line_style(FL_SOLID, 3, NULL); | |||
| #if !__APPLE__ | |||
| XSetFunction(fl_display,fl_gc,GXxor); | |||
| #endif | |||
| fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY); | |||
| fl_color(FL_BLUE); | |||
| @@ -200,7 +202,9 @@ void Fl_Loop::DrawPosMarker() | |||
| fl_line(m_IndSX,m_IndSY,m_IndEX,m_IndEY); | |||
| fl_line_style(FL_SOLID, 1, NULL); | |||
| #if !__APPLE__ | |||
| XSetFunction(fl_display,fl_gc,GXcopy); | |||
| #endif | |||
| } | |||
| if (m_PosMarkerCount>POSMARKER_MAX) | |||
| @@ -40,7 +40,8 @@ public: | |||
| // has to be defined in the plugin | |||
| virtual void UpdateGUI() { Fl::check(); } | |||
| enum Type{SINE,SQUARE,SAW,REVSAW,TRIANGLE,PULSE1,PULSE2,INVSINE}; | |||
| typedef char Type; | |||
| enum {SINE,SQUARE,SAW,REVSAW,TRIANGLE,PULSE1,PULSE2,INVSINE}; | |||
| void WriteWaves(); | |||
| void NoteTrigger(int V,int s,int v); | |||
| @@ -34,8 +34,8 @@ int LINE_COLOUR;// = 140; | |||
| //////////////////////////////////////////////////////////////////// | |||
| Fl_EventMap::Fl_EventMap(int x, int y, int w, int h, const char* label) : | |||
| Fl_Group(x,y,w,h,label), | |||
| Fl_EventMap::Fl_EventMap(int x, int y, int ww, int h, const char* label) : | |||
| Fl_Group(x,y,ww,h,label), | |||
| m_Type(ARRANGE_MAP), | |||
| m_Update(true), | |||
| m_Zoom(1.0f), | |||
| @@ -62,6 +62,7 @@ m_FirstUpdate(true) | |||
| LINE_COLOUR=fl_color(); | |||
| fl_color(200,200,200); | |||
| // SpiralSound/Plugins/Widgets/Fl_EventMap.C:65: declaration of `w' shadows a parameter | |||
| int w=fl_color(); | |||
| fl_color(50,50,50); | |||
| int b=fl_color(); | |||
| @@ -263,12 +264,14 @@ void Fl_EventMap::SetTime(float Time) | |||
| int Depth=parent()->h(); | |||
| if (DrawPos>Left && DrawPos<Left+Width) | |||
| { | |||
| { | |||
| #if !__APPLE__ | |||
| XSetFunction(fl_display,fl_gc,GXxor); | |||
| XSetForeground(fl_display, fl_gc, 0xff00ffff); | |||
| if (!m_FirstUpdate) fl_line(m_LastPos,Top,m_LastPos,Depth); | |||
| fl_line(DrawPos,Top,DrawPos,Depth); | |||
| XSetFunction(fl_display,fl_gc,GXcopy); | |||
| #endif | |||
| m_LastPos=DrawPos; | |||
| } | |||
| } | |||
| @@ -32,9 +32,11 @@ | |||
| const int HEADERLEN = (4+24+8); | |||
| #if __BYTE_ORDER == BIG_ENDIAN | |||
| #define SWAPSHORT(a) (a)=(((a)<<8)|((a)>>8)) | |||
| #define SWAPSHORT(a) (a)=(((a)<<8)|(((a)>>8)&0xff)) | |||
| #define SWAPINT(a) (a)=(((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|(((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24) | |||
| #else | |||
| #define SWAPSHORT(a) | |||
| #define SWAPINT(a) | |||
| #endif | |||
| int WavFile::Open(string FileName, Mode mode, Channels channels) | |||
| @@ -92,7 +94,6 @@ int WavFile::Open(string FileName, Mode mode, Channels channels) | |||
| m_DataHeader.DataLengthBytes=0; | |||
| #if __BYTE_ORDER == BIG_ENDIAN | |||
| SWAPINT(m_Header.RiffFileLength); | |||
| SWAPINT(m_Header.FmtLength); | |||
| SWAPSHORT(m_Header.FmtTag); | |||
| @@ -102,7 +103,6 @@ int WavFile::Open(string FileName, Mode mode, Channels channels) | |||
| SWAPSHORT(m_Header.FmtBlockAlign); | |||
| SWAPSHORT(m_Header.FmtBitsPerSample); | |||
| SWAPINT(m_DataHeader.DataLengthBytes); | |||
| #endif | |||
| fwrite(&m_Header,1,sizeof(CanonicalWavHeader),m_Stream); | |||
| fwrite(&m_DataHeader,1,sizeof(DataHeader),m_Stream); | |||
| @@ -113,7 +113,16 @@ int WavFile::Open(string FileName, Mode mode, Channels channels) | |||
| if (mode==READ) | |||
| { | |||
| fread(&m_Header,sizeof(CanonicalWavHeader),1,m_Stream); | |||
| SWAPINT(m_Header.RiffFileLength); | |||
| SWAPINT(m_Header.FmtLength); | |||
| SWAPSHORT(m_Header.FmtTag); | |||
| SWAPSHORT(m_Header.FmtChannels); | |||
| SWAPINT(m_Header.FmtSamplerate); | |||
| SWAPINT(m_Header.FmtBytesPerSec); | |||
| SWAPSHORT(m_Header.FmtBlockAlign); | |||
| SWAPSHORT(m_Header.FmtBitsPerSample); | |||
| #ifdef TRACE_OUT | |||
| cerr<<FileName<<endl; | |||
| cerr<<"RiffFileLength "<<m_Header.RiffFileLength<<endl; | |||
| @@ -133,7 +142,9 @@ int WavFile::Open(string FileName, Mode mode, Channels channels) | |||
| } | |||
| fread(&m_DataHeader,sizeof(DataHeader),1,m_Stream); | |||
| SWAPINT(m_DataHeader.DataLengthBytes); | |||
| while (m_DataHeader.DataName[0]!='d' || | |||
| m_DataHeader.DataName[1]!='a' || | |||
| m_DataHeader.DataName[2]!='t' || | |||
| @@ -206,10 +217,15 @@ int WavFile::Save(Sample &data) | |||
| float v=data[n]; | |||
| if (v<-1) v=-1; if (v>1) v=1; | |||
| temp[n]=(short)(v*SHRT_MAX); | |||
| SWAPSHORT(temp[n]); | |||
| } | |||
| m_DataHeader.DataLengthBytes+=data.GetLength()*2; | |||
| fwrite(temp,sizeof(&temp),data.GetLength()/2,m_Stream); | |||
| // leak! | |||
| delete[] temp; | |||
| return 1; | |||
| } | |||
| @@ -270,7 +286,9 @@ int WavFile::Load(Sample &data) | |||
| long value=0; | |||
| for (int i=0; i<m_Header.FmtChannels; i++) | |||
| { | |||
| value+=TempBuf[(n*m_Header.FmtChannels)+i]; | |||
| short s = TempBuf[(n*m_Header.FmtChannels)+i]; | |||
| SWAPSHORT(s); | |||
| value+=s; | |||
| } | |||
| value/=m_Header.FmtChannels; | |||
| @@ -280,7 +298,7 @@ int WavFile::Load(Sample &data) | |||
| m_DataHeader.DataLengthBytes /= m_Header.FmtChannels; | |||
| m_Header.FmtChannels=1; | |||
| delete TempBuf; | |||
| delete[] TempBuf; | |||
| } | |||
| else // it's mono. | |||
| { | |||
| @@ -294,10 +312,12 @@ int WavFile::Load(Sample &data) | |||
| for (int n=0; n<GetSize(); n++) | |||
| { | |||
| data.Set(n,TempBuf[n]/(float)SHRT_MAX); | |||
| short s = TempBuf[n]; | |||
| SWAPSHORT(s); | |||
| data.Set(n,s/(float)SHRT_MAX); | |||
| } | |||
| delete TempBuf; | |||
| delete[] TempBuf; | |||
| } | |||
| return 1; | |||
| @@ -324,7 +344,9 @@ int WavFile::Load(short *data) | |||
| long value=0; | |||
| for (int i=0; i<m_Header.FmtChannels; i++) | |||
| { | |||
| value+=TempBuf[(n*m_Header.FmtChannels)+i]; | |||
| short s = TempBuf[(n*m_Header.FmtChannels)+i]; | |||
| SWAPSHORT(s); | |||
| value+=s; | |||
| } | |||
| value/=m_Header.FmtChannels; | |||
| @@ -334,13 +356,18 @@ int WavFile::Load(short *data) | |||
| m_DataHeader.DataLengthBytes /= m_Header.FmtChannels; | |||
| m_Header.FmtChannels=1; | |||
| delete TempBuf; | |||
| delete[] TempBuf; | |||
| } | |||
| else // we can read the data directly in, it's mono. | |||
| { | |||
| if (m_DataHeader.DataLengthBytes== | |||
| (int)fread(data,1,m_DataHeader.DataLengthBytes,m_Stream)) | |||
| { | |||
| #if __BYTE_ORDER == BIG_ENDIAN | |||
| short *TempBuf = (short*)data; | |||
| for (int n=0; n < m_DataHeader.DataLengthBytes / 2; n++) | |||
| SWAPSHORT(TempBuf[n]); | |||
| #endif | |||
| return 1; | |||
| } | |||
| @@ -389,7 +416,7 @@ int WavFile::LoadChunk(int NumSamples, Sample &ldata, Sample &rdata) | |||
| rdata.Set(n,TempBuf[(n*2)+1]/(float)SHRT_MAX); | |||
| } | |||
| delete TempBuf; | |||
| delete[] TempBuf; | |||
| } | |||
| else // we can read the data directly in, it's mono. | |||
| { | |||
| @@ -24,6 +24,12 @@ | |||
| #include <stdio.h> | |||
| #include "Sample.h" | |||
| #if __APPLE__ | |||
| // this is the traditional way of setting 2 bytes alignment | |||
| // else the apple compiler might use 4, or even 8 | |||
| #pragma options align=mac68k | |||
| #endif | |||
| struct CanonicalWavHeader | |||
| { | |||
| char RiffName[4]; | |||
| @@ -46,6 +52,10 @@ struct DataHeader | |||
| int DataLengthBytes; | |||
| }; | |||
| #if __APPLE__ | |||
| #pragma options align=reset | |||
| #endif | |||
| class WavFile | |||
| { | |||
| public: | |||
| @@ -125,6 +125,11 @@ void SpiralSynthModularInfo::StreamInPrefs(istream &s) | |||
| s>>st; | |||
| if (st!="end") PLUGINVEC.push_back(st); | |||
| } | |||
| #if __APPLE__ | |||
| // ignore custom paths, plugins are encapsulated in the app anyway | |||
| // this prevents the program to fail if the user move the application icon | |||
| PLUGIN_PATH = PLUGIN_PATH_LOCATION; | |||
| #endif | |||
| } | |||
| void SpiralSynthModularInfo::StreamOutPrefs(ostream &s) | |||
| @@ -99,9 +99,29 @@ void audioloop(void* o) | |||
| } | |||
| ////////////////////////////////////////////////////// | |||
| #if __APPLE__ | |||
| #include <CoreFoundation/CFBundle.h> | |||
| #include <libgen.h> | |||
| #endif | |||
| int main(int argc, char **argv) | |||
| { | |||
| { | |||
| #if __APPLE__ | |||
| // --with-plugindir=./Libraries | |||
| system("pwd"); | |||
| CFBundleRef main = CFBundleGetMainBundle(); | |||
| CFURLRef url = main ? CFBundleCopyExecutableURL(main) : NULL; | |||
| CFStringRef path = url ? CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle) : NULL; | |||
| char * dst = (char*)CFStringGetCStringPtr(path, 0); | |||
| printf("main %p url %p path %p dst %p", main, url, path, dst); | |||
| if (dst) { | |||
| printf("Have a valid name '%s'\n", dst); | |||
| chdir(dirname(dst)); | |||
| chdir(".."); | |||
| } else | |||
| printf("No base pathname\n"); | |||
| #endif | |||
| srand(time(NULL)); | |||
| SpiralSynthModularInfo::Get()->LoadPrefs(); | |||