@@ -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(); | |||