| @@ -26,7 +26,7 @@ ifeq ($(CONFIG),Release) | |||
| OBJDIR := ../../bin/intermediate_linux/Release | |||
| OUTDIR := ../../bin | |||
| CPPFLAGS := -MMD -D "LINUX=1" -D "NDEBUG=1" -I "../../" -I "/usr/include" -I "/usr/include/freetype2" | |||
| CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O2 -Wall | |||
| CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O2 -O2 -Wall -fvisibility=hidden | |||
| CXXFLAGS := $(CFLAGS) | |||
| LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -s | |||
| LDDEPS := | |||
| @@ -60,6 +60,7 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_Socket.o \ | |||
| $(OBJDIR)/juce_URL.o \ | |||
| $(OBJDIR)/juce_BufferedInputStream.o \ | |||
| $(OBJDIR)/juce_FileInputSource.o \ | |||
| $(OBJDIR)/juce_GZIPCompressorOutputStream.o \ | |||
| $(OBJDIR)/juce_GZIPDecompressorInputStream.o \ | |||
| $(OBJDIR)/juce_MemoryInputStream.o \ | |||
| @@ -126,6 +127,8 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_AudioFormat.o \ | |||
| $(OBJDIR)/juce_AudioFormatManager.o \ | |||
| $(OBJDIR)/juce_AudioSubsectionReader.o \ | |||
| $(OBJDIR)/juce_AudioThumbnail.o \ | |||
| $(OBJDIR)/juce_AudioThumbnailCache.o \ | |||
| $(OBJDIR)/juce_FlacAudioFormat.o \ | |||
| $(OBJDIR)/juce_OggVorbisAudioFormat.o \ | |||
| $(OBJDIR)/juce_WavAudioFormat.o \ | |||
| @@ -568,6 +571,11 @@ $(OBJDIR)/juce_BufferedInputStream.o: ../../src/juce_core/io/streams/juce_Buffer | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_FileInputSource.o: ../../src/juce_core/io/streams/juce_FileInputSource.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_GZIPCompressorOutputStream.o: ../../src/juce_core/io/streams/juce_GZIPCompressorOutputStream.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @@ -898,6 +906,16 @@ $(OBJDIR)/juce_AudioSubsectionReader.o: ../../src/juce_appframework/audio/audio_ | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_AudioThumbnail.o: ../../src/juce_appframework/audio/audio_file_formats/juce_AudioThumbnail.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_AudioThumbnailCache.o: ../../src/juce_appframework/audio/audio_file_formats/juce_AudioThumbnailCache.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_FlacAudioFormat.o: ../../src/juce_appframework/audio/audio_file_formats/juce_FlacAudioFormat.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @@ -57,48 +57,22 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/basics/juce_Time.h" | |||
| #include "../../../src/juce_core/io/network/juce_URL.h" | |||
| #include "../../../src/juce_core/io/files/juce_NamedPipe.h" | |||
| static File executableFile; | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| //============================================================================== | |||
| bool juce_isDirectory (const String& fileName) throw() | |||
| { | |||
| if (fileName.isEmpty()) | |||
| return true; | |||
| struct stat info; | |||
| const int res = stat (fileName.toUTF8(), &info); | |||
| if (res == 0) | |||
| return (info.st_mode & S_IFDIR) != 0; | |||
| return false; | |||
| } | |||
| bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw() | |||
| { | |||
| if (fileName.isEmpty()) | |||
| return false; | |||
| bool exists = access (fileName.toUTF8(), F_OK) == 0; | |||
| if (exists && dontCountDirectories && juce_isDirectory (fileName)) | |||
| exists = false; | |||
| /* | |||
| Note that a lot of methods that you'd expect to find in this file actually | |||
| live in juce_posix_SharedCode.cpp! | |||
| */ | |||
| #include "../../macosx/platform_specific_code/juce_posix_SharedCode.cpp" | |||
| return exists; | |||
| } | |||
| int64 juce_getFileSize (const String& fileName) throw() | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fileName.toUTF8(), &info); | |||
| if (res == 0) | |||
| return info.st_size; | |||
| //============================================================================== | |||
| static File executableFile; | |||
| return 0; | |||
| } | |||
| //============================================================================== | |||
| void juce_getFileTimes (const String& fileName, | |||
| int64& modificationTime, | |||
| int64& accessTime, | |||
| @@ -112,10 +86,6 @@ void juce_getFileTimes (const String& fileName, | |||
| const int res = stat (fileName.toUTF8(), &info); | |||
| if (res == 0) | |||
| { | |||
| /* | |||
| * Note: On Linux the st_ctime field is defined as last change time | |||
| * rather than creation. | |||
| */ | |||
| modificationTime = (int64) info.st_mtime * 1000; | |||
| accessTime = (int64) info.st_atime * 1000; | |||
| creationTime = (int64) info.st_ctime * 1000; | |||
| @@ -134,11 +104,6 @@ bool juce_setFileTimes (const String& fileName, | |||
| return utime (fileName.toUTF8(), ×) == 0; | |||
| } | |||
| bool juce_canWriteToFile (const String& fileName) throw() | |||
| { | |||
| return access (fileName.toUTF8(), W_OK) == 0; | |||
| } | |||
| bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw() | |||
| { | |||
| struct stat info; | |||
| @@ -157,14 +122,6 @@ bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw() | |||
| return chmod (fileName.toUTF8(), info.st_mode) == 0; | |||
| } | |||
| bool juce_deleteFile (const String& fileName) throw() | |||
| { | |||
| if (juce_isDirectory (fileName)) | |||
| return rmdir (fileName.toUTF8()) == 0; | |||
| else | |||
| return remove (fileName.toUTF8()) == 0; | |||
| } | |||
| bool juce_copyFile (const String& s, const String& d) throw() | |||
| { | |||
| const File source (s), dest (d); | |||
| @@ -196,97 +153,6 @@ bool juce_copyFile (const String& s, const String& d) throw() | |||
| return ok; | |||
| } | |||
| bool juce_moveFile (const String& source, const String& dest) throw() | |||
| { | |||
| if (rename (source.toUTF8(), dest.toUTF8()) == 0) | |||
| return true; | |||
| if (! juce_canWriteToFile (source)) | |||
| return false; | |||
| if (juce_copyFile (source, dest)) | |||
| { | |||
| if (juce_deleteFile (source)) | |||
| return true; | |||
| juce_deleteFile (dest); | |||
| } | |||
| return false; | |||
| } | |||
| void juce_createDirectory (const String& fileName) throw() | |||
| { | |||
| mkdir (fileName.toUTF8(), 0777); | |||
| } | |||
| void* juce_fileOpen (const String& fileName, bool forWriting) throw() | |||
| { | |||
| const char* mode = "rb"; | |||
| if (forWriting) | |||
| { | |||
| if (juce_fileExists (fileName, false)) | |||
| { | |||
| FILE* f = fopen (fileName.toUTF8(), "r+b"); | |||
| if (f != 0) | |||
| fseek (f, 0, SEEK_END); | |||
| return (void*) f; | |||
| } | |||
| else | |||
| { | |||
| mode = "w+b"; | |||
| } | |||
| } | |||
| return (void*)fopen (fileName.toUTF8(), mode); | |||
| } | |||
| void juce_fileClose (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| fclose ((FILE*) handle); | |||
| } | |||
| int juce_fileRead (void* handle, void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return fread (buffer, 1, size, (FILE*) handle); | |||
| return 0; | |||
| } | |||
| int juce_fileWrite (void* handle, const void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return fwrite (buffer, 1, size, (FILE*) handle); | |||
| return 0; | |||
| } | |||
| int64 juce_fileSetPosition (void* handle, int64 pos) throw() | |||
| { | |||
| if (handle != 0 && fseek ((FILE*) handle, (long) pos, SEEK_SET) == 0) | |||
| return pos; | |||
| return -1; | |||
| } | |||
| int64 juce_fileGetPosition (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| return ftell ((FILE*) handle); | |||
| else | |||
| return -1; | |||
| } | |||
| void juce_fileFlush (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| fflush ((FILE*) handle); | |||
| } | |||
| const StringArray juce_getFileSystemRoots() throw() | |||
| { | |||
| StringArray s; | |||
| @@ -294,28 +160,7 @@ const StringArray juce_getFileSystemRoots() throw() | |||
| return s; | |||
| } | |||
| const String juce_getVolumeLabel (const String& filenameOnVolume, | |||
| int& volumeSerialNumber) throw() | |||
| { | |||
| // There is no equivalent on Linux | |||
| volumeSerialNumber = 0; | |||
| return String::empty; | |||
| } | |||
| int64 File::getBytesFreeOnVolume() const throw() | |||
| { | |||
| struct statfs buf; | |||
| int64 free_space = 0; | |||
| if (statfs (getFullPathName().toUTF8(), &buf) == 0) | |||
| { | |||
| // Note: this returns space available to non-super user | |||
| free_space = (int64) buf.f_bsize * (int64) buf.f_bavail; | |||
| } | |||
| return free_space; | |||
| } | |||
| //============================================================================== | |||
| bool File::isOnCDRomDrive() const throw() | |||
| { | |||
| struct statfs buf; | |||
| @@ -353,7 +198,6 @@ bool File::isOnHardDisk() const throw() | |||
| return true; | |||
| } | |||
| //============================================================================== | |||
| const File File::getSpecialLocation (const SpecialLocationType type) | |||
| { | |||
| @@ -439,10 +283,6 @@ bool File::setAsCurrentWorkingDirectory() const throw() | |||
| return chdir (getFullPathName().toUTF8()) == 0; | |||
| } | |||
| //============================================================================== | |||
| const tchar File::separator = T('/'); | |||
| const tchar* File::separatorString = T("/"); | |||
| //============================================================================== | |||
| struct FindFileStruct | |||
| { | |||
| @@ -40,12 +40,17 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/threads/juce_CriticalSection.h" | |||
| #include "../../../src/juce_core/threads/juce_WaitableEvent.h" | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/threads/juce_Process.h" | |||
| #include "../../../src/juce_core/io/files/juce_File.h" | |||
| #include "../../../src/juce_core/basics/juce_SystemStats.h" | |||
| //============================================================================== | |||
| /* | |||
| Note that a lot of methods that you'd expect to find in this file actually | |||
| live in juce_posix_SharedCode.cpp! | |||
| */ | |||
| #ifndef CPU_ISSET | |||
| #undef SUPPORT_AFFINITIES | |||
| #endif | |||
| @@ -169,143 +174,6 @@ void Thread::yield() throw() | |||
| sched_yield(); | |||
| } | |||
| void JUCE_CALLTYPE Thread::sleep (int millisecs) throw() | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = millisecs / 1000; | |||
| time.tv_nsec = (millisecs % 1000) * 1000000; | |||
| nanosleep (&time, 0); | |||
| } | |||
| //============================================================================== | |||
| CriticalSection::CriticalSection() throw() | |||
| { | |||
| pthread_mutexattr_t atts; | |||
| pthread_mutexattr_init (&atts); | |||
| pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE); | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() throw() | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const throw() | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const throw() | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const throw() | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| } | |||
| //============================================================================== | |||
| struct EventStruct | |||
| { | |||
| pthread_cond_t condition; | |||
| pthread_mutex_t mutex; | |||
| bool triggered; | |||
| }; | |||
| WaitableEvent::WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = new EventStruct(); | |||
| es->triggered = false; | |||
| pthread_cond_init (&es->condition, 0); | |||
| pthread_mutex_init (&es->mutex, 0); | |||
| internal = es; | |||
| } | |||
| WaitableEvent::~WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*)internal; | |||
| pthread_cond_destroy (&es->condition); | |||
| pthread_mutex_destroy (&es->mutex); | |||
| delete es; | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*)internal; | |||
| bool ok = true; | |||
| pthread_mutex_lock (&es->mutex); | |||
| if (! es->triggered) | |||
| { | |||
| if (timeOutMillisecs < 0) | |||
| { | |||
| pthread_cond_wait (&es->condition, &es->mutex); | |||
| } | |||
| else | |||
| { | |||
| struct timespec time; | |||
| struct timeval t; | |||
| int timeout = 0; | |||
| gettimeofday (&t, 0); | |||
| time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000); | |||
| time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000; | |||
| while (time.tv_nsec >= 1000000000) | |||
| { | |||
| time.tv_nsec -= 1000000000; | |||
| time.tv_sec++; | |||
| } | |||
| while (! timeout) | |||
| { | |||
| timeout = pthread_cond_timedwait (&es->condition, &es->mutex, &time); | |||
| if (! timeout) | |||
| // Success | |||
| break; | |||
| if (timeout == EINTR) | |||
| // Go round again | |||
| timeout = 0; | |||
| } | |||
| } | |||
| ok = es->triggered; | |||
| } | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| return ok; | |||
| } | |||
| void WaitableEvent::signal() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*)internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = true; | |||
| pthread_cond_broadcast (&es->condition); | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| void WaitableEvent::reset() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*)internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| //============================================================================== | |||
| // sets the process to 0=low priority, 1=normal, 2=high, 3=realtime | |||
| @@ -404,82 +272,4 @@ void* Process::getProcedureEntryPoint (void* libraryHandle, const String& proced | |||
| #endif | |||
| //============================================================================== | |||
| InterProcessLock::InterProcessLock (const String& name_) throw() | |||
| : internal (0), | |||
| name (name_), | |||
| reentrancyLevel (0) | |||
| { | |||
| const File tempDir (File::getSpecialLocation (File::tempDirectory)); | |||
| const File temp (tempDir.getChildFile (name)); | |||
| temp.create(); | |||
| internal = (void*) open (temp.getFullPathName().toUTF8(), 'a'); | |||
| } | |||
| InterProcessLock::~InterProcessLock() throw() | |||
| { | |||
| while (reentrancyLevel > 0) | |||
| this->exit(); | |||
| #if JUCE_64BIT | |||
| close ((long long) internal); | |||
| #else | |||
| close ((int) internal); | |||
| #endif | |||
| } | |||
| bool InterProcessLock::enter (const int timeOutMillisecs) throw() | |||
| { | |||
| if (internal == 0) | |||
| return false; | |||
| if (reentrancyLevel != 0) | |||
| return true; | |||
| if (timeOutMillisecs <= 0) | |||
| { | |||
| if (flock ((long) internal, | |||
| timeOutMillisecs < 0 ? LOCK_EX | |||
| : (LOCK_EX | LOCK_NB)) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
| for (;;) | |||
| { | |||
| if (flock ((long) internal, LOCK_EX | LOCK_NB) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| if (Time::currentTimeMillis() >= endTime) | |||
| break; | |||
| Thread::sleep (10); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void InterProcessLock::exit() throw() | |||
| { | |||
| if (reentrancyLevel > 0 && internal != 0) | |||
| { | |||
| --reentrancyLevel; | |||
| const int result = flock ((long) internal, LOCK_UN); | |||
| (void) result; | |||
| jassert (result == 0); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -50,12 +50,18 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/basics/juce_SystemStats.h" | |||
| #include "../../../src/juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../src/juce_core/io/files/juce_NamedPipe.h" | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| //============================================================================== | |||
| const tchar File::separator = T('/'); | |||
| const tchar* File::separatorString = T("/"); | |||
| /* | |||
| Note that a lot of methods that you'd expect to find in this file actually | |||
| live in juce_posix_SharedCode.cpp! | |||
| */ | |||
| #include "juce_posix_SharedCode.cpp" | |||
| //============================================================================== | |||
| static File executableFile; | |||
| @@ -193,54 +199,6 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) | |||
| } | |||
| //============================================================================== | |||
| static bool juce_stat (const String& fileName, struct stat& info) throw() | |||
| { | |||
| return fileName.isNotEmpty() | |||
| && (stat (fileName.toUTF8(), &info) == 0); | |||
| } | |||
| //============================================================================== | |||
| bool juce_isDirectory (const String& fileName) throw() | |||
| { | |||
| if (fileName.isEmpty()) | |||
| return true; | |||
| struct stat info; | |||
| return juce_stat (fileName, info) | |||
| && ((info.st_mode & S_IFDIR) != 0); | |||
| } | |||
| bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw() | |||
| { | |||
| if (fileName.isEmpty()) | |||
| return false; | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| bool exists = access (fileNameUTF8, F_OK) == 0; | |||
| if (exists && dontCountDirectories) | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fileNameUTF8, &info); | |||
| if (res == 0 && (info.st_mode & S_IFDIR) != 0) | |||
| exists = false; | |||
| } | |||
| return exists; | |||
| } | |||
| int64 juce_getFileSize (const String& fileName) throw() | |||
| { | |||
| struct stat info; | |||
| if (juce_stat (fileName, info)) | |||
| return info.st_size; | |||
| return 0; | |||
| } | |||
| const unsigned int macTimeToUnixTimeDiff = 0x7c25be90; | |||
| static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw() | |||
| @@ -328,11 +286,6 @@ bool juce_setFileTimes (const String& fileName, | |||
| return false; | |||
| } | |||
| bool juce_canWriteToFile (const String& fileName) throw() | |||
| { | |||
| return access (fileName.toUTF8(), W_OK) == 0; | |||
| } | |||
| bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw() | |||
| { | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| @@ -358,16 +311,6 @@ bool juce_setFileReadOnly (const String& fileName, bool isReadOnly) throw() | |||
| return ok; | |||
| } | |||
| bool juce_deleteFile (const String& fileName) throw() | |||
| { | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| if (juce_isDirectory (fileName)) | |||
| return rmdir (fileNameUTF8) == 0; | |||
| else | |||
| return remove (fileNameUTF8) == 0; | |||
| } | |||
| bool juce_copyFile (const String& src, const String& dst) throw() | |||
| { | |||
| const File destFile (dst); | |||
| @@ -446,97 +389,6 @@ bool juce_copyFile (const String& src, const String& dst) throw() | |||
| return false; | |||
| } | |||
| bool juce_moveFile (const String& source, const String& dest) throw() | |||
| { | |||
| if (rename (source.toUTF8(), dest.toUTF8()) == 0) | |||
| return true; | |||
| if (juce_canWriteToFile (source) | |||
| && juce_copyFile (source, dest)) | |||
| { | |||
| if (juce_deleteFile (source)) | |||
| return true; | |||
| juce_deleteFile (dest); | |||
| } | |||
| return false; | |||
| } | |||
| void juce_createDirectory (const String& fileName) throw() | |||
| { | |||
| mkdir (fileName.toUTF8(), 0777); | |||
| } | |||
| void* juce_fileOpen (const String& fileName, bool forWriting) throw() | |||
| { | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| int flags = O_RDONLY; | |||
| if (forWriting) | |||
| { | |||
| if (juce_fileExists (fileName, false)) | |||
| { | |||
| const int f = open (fileNameUTF8, O_RDWR, 00644); | |||
| if (f != -1) | |||
| lseek (f, 0, SEEK_END); | |||
| return (void*) f; | |||
| } | |||
| else | |||
| { | |||
| flags = O_RDWR + O_CREAT; | |||
| } | |||
| } | |||
| return (void*) open (fileNameUTF8, flags, 00644); | |||
| } | |||
| void juce_fileClose (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| close ((int) handle); | |||
| } | |||
| int juce_fileRead (void* handle, void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return read ((int) handle, buffer, size); | |||
| return 0; | |||
| } | |||
| int juce_fileWrite (void* handle, const void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return write ((int) handle, buffer, size); | |||
| return 0; | |||
| } | |||
| int64 juce_fileSetPosition (void* handle, int64 pos) throw() | |||
| { | |||
| if (handle != 0 && lseek ((int) handle, pos, SEEK_SET) == pos) | |||
| return pos; | |||
| return -1; | |||
| } | |||
| int64 juce_fileGetPosition (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| return lseek ((int) handle, 0, SEEK_CUR); | |||
| else | |||
| return -1; | |||
| } | |||
| void juce_fileFlush (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| fsync ((int) handle); | |||
| } | |||
| const StringArray juce_getFileSystemRoots() throw() | |||
| { | |||
| StringArray s; | |||
| @@ -544,40 +396,6 @@ const StringArray juce_getFileSystemRoots() throw() | |||
| return s; | |||
| } | |||
| const String juce_getVolumeLabel (const String& filenameOnVolume, int& volumeSerialNumber) throw() | |||
| { | |||
| volumeSerialNumber = 0; | |||
| return String::empty; | |||
| } | |||
| // if this file doesn't exist, find a parent of it that does.. | |||
| static bool doStatFS (const File* file, struct statfs& result) throw() | |||
| { | |||
| File f (*file); | |||
| for (int i = 5; --i >= 0;) | |||
| { | |||
| if (f.exists()) | |||
| break; | |||
| f = f.getParentDirectory(); | |||
| } | |||
| return statfs (f.getFullPathName().toUTF8(), &result) == 0; | |||
| } | |||
| int64 File::getBytesFreeOnVolume() const throw() | |||
| { | |||
| int64 free_space = 0; | |||
| struct statfs buf; | |||
| if (doStatFS (this, buf)) | |||
| // Note: this returns space available to non-super user | |||
| free_space = (int64) buf.f_bsize * (int64) buf.f_bavail; | |||
| return free_space; | |||
| } | |||
| //============================================================================== | |||
| static bool isFileOnDriveType (const File* const f, const char** types) throw() | |||
| { | |||
| @@ -609,6 +427,7 @@ bool File::isOnHardDisk() const throw() | |||
| return ! (isOnCDRomDrive() || isFileOnDriveType (this, (const char**) nonHDTypes)); | |||
| } | |||
| //============================================================================== | |||
| const File File::getSpecialLocation (const SpecialLocationType type) | |||
| { | |||
| @@ -43,117 +43,14 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/threads/juce_WaitableEvent.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/threads/juce_Process.h" | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../src/juce_core/io/files/juce_File.h" | |||
| //============================================================================== | |||
| CriticalSection::CriticalSection() throw() | |||
| { | |||
| pthread_mutexattr_t atts; | |||
| pthread_mutexattr_init (&atts); | |||
| pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE); | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() throw() | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const throw() | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const throw() | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const throw() | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| } | |||
| //============================================================================== | |||
| struct EventStruct | |||
| { | |||
| pthread_cond_t condition; | |||
| pthread_mutex_t mutex; | |||
| bool triggered; | |||
| }; | |||
| WaitableEvent::WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = new EventStruct(); | |||
| es->triggered = false; | |||
| pthread_cond_init (&es->condition, 0); | |||
| pthread_mutex_init (&es->mutex, 0); | |||
| internal = es; | |||
| } | |||
| WaitableEvent::~WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_cond_destroy (&es->condition); | |||
| pthread_mutex_destroy (&es->mutex); | |||
| delete es; | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| bool ok = true; | |||
| pthread_mutex_lock (&es->mutex); | |||
| if (! es->triggered) | |||
| { | |||
| if (timeOutMillisecs < 0) | |||
| { | |||
| pthread_cond_wait (&es->condition, &es->mutex); | |||
| } | |||
| else | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = timeOutMillisecs / 1000; | |||
| time.tv_nsec = (timeOutMillisecs % 1000) * 1000000; | |||
| pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time); | |||
| } | |||
| ok = es->triggered; | |||
| } | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| return ok; | |||
| } | |||
| void WaitableEvent::signal() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = true; | |||
| pthread_cond_broadcast (&es->condition); | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| void WaitableEvent::reset() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| /* | |||
| Note that a lot of methods that you'd expect to find in this file actually | |||
| live in juce_posix_SharedCode.cpp! | |||
| */ | |||
| //============================================================================== | |||
| void JUCE_API juce_threadEntryPoint (void*); | |||
| @@ -215,15 +112,6 @@ void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw() | |||
| jassertfalse | |||
| } | |||
| void JUCE_CALLTYPE Thread::sleep (int millisecs) throw() | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = millisecs / 1000; | |||
| time.tv_nsec = (millisecs % 1000) * 1000000; | |||
| nanosleep (&time, 0); | |||
| } | |||
| //============================================================================== | |||
| bool JUCE_CALLTYPE juce_isRunningUnderDebugger() throw() | |||
| { | |||
| @@ -311,77 +199,5 @@ void* Process::getProcedureEntryPoint (void* h, const String& procedureName) | |||
| return 0; | |||
| } | |||
| //============================================================================== | |||
| InterProcessLock::InterProcessLock (const String& name_) throw() | |||
| : internal (0), | |||
| name (name_), | |||
| reentrancyLevel (0) | |||
| { | |||
| const File tempDir (File::getSpecialLocation (File::tempDirectory)); | |||
| const File temp (tempDir.getChildFile (name)); | |||
| temp.create(); | |||
| internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY); | |||
| } | |||
| InterProcessLock::~InterProcessLock() throw() | |||
| { | |||
| while (reentrancyLevel > 0) | |||
| this->exit(); | |||
| close ((int) internal); | |||
| } | |||
| bool InterProcessLock::enter (const int timeOutMillisecs) throw() | |||
| { | |||
| if (internal == 0) | |||
| return false; | |||
| if (reentrancyLevel != 0) | |||
| return true; | |||
| if (timeOutMillisecs <= 0) | |||
| { | |||
| if (flock ((int) internal, | |||
| timeOutMillisecs < 0 ? LOCK_EX | |||
| : (LOCK_EX | LOCK_NB)) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
| for (;;) | |||
| { | |||
| if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| if (Time::currentTimeMillis() >= endTime) | |||
| break; | |||
| Thread::sleep (10); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void InterProcessLock::exit() throw() | |||
| { | |||
| if (reentrancyLevel > 0 && internal != 0) | |||
| { | |||
| --reentrancyLevel; | |||
| const int result = flock ((int) internal, LOCK_UN); | |||
| (void) result; | |||
| jassert (result == 0); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -0,0 +1,466 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE 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 General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| /* | |||
| This file contains posix routines that are common to both the Linux and Mac builds. | |||
| It gets included directly in the cpp files for these platforms. | |||
| */ | |||
| //============================================================================== | |||
| CriticalSection::CriticalSection() throw() | |||
| { | |||
| pthread_mutexattr_t atts; | |||
| pthread_mutexattr_init (&atts); | |||
| pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE); | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() throw() | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const throw() | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const throw() | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const throw() | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| } | |||
| //============================================================================== | |||
| struct EventStruct | |||
| { | |||
| pthread_cond_t condition; | |||
| pthread_mutex_t mutex; | |||
| bool triggered; | |||
| }; | |||
| WaitableEvent::WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = new EventStruct(); | |||
| es->triggered = false; | |||
| pthread_cond_init (&es->condition, 0); | |||
| pthread_mutex_init (&es->mutex, 0); | |||
| internal = es; | |||
| } | |||
| WaitableEvent::~WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_cond_destroy (&es->condition); | |||
| pthread_mutex_destroy (&es->mutex); | |||
| delete es; | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| bool ok = true; | |||
| pthread_mutex_lock (&es->mutex); | |||
| if (! es->triggered) | |||
| { | |||
| if (timeOutMillisecs < 0) | |||
| { | |||
| pthread_cond_wait (&es->condition, &es->mutex); | |||
| } | |||
| else | |||
| { | |||
| struct timespec time; | |||
| #if JUCE_MAC | |||
| time.tv_sec = timeOutMillisecs / 1000; | |||
| time.tv_nsec = (timeOutMillisecs % 1000) * 1000000; | |||
| pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time); | |||
| #else | |||
| struct timeval t; | |||
| int timeout = 0; | |||
| gettimeofday (&t, 0); | |||
| time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000); | |||
| time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000; | |||
| while (time.tv_nsec >= 1000000000) | |||
| { | |||
| time.tv_nsec -= 1000000000; | |||
| time.tv_sec++; | |||
| } | |||
| while (! timeout) | |||
| { | |||
| timeout = pthread_cond_timedwait (&es->condition, &es->mutex, &time); | |||
| if (! timeout) | |||
| // Success | |||
| break; | |||
| if (timeout == EINTR) | |||
| // Go round again | |||
| timeout = 0; | |||
| } | |||
| #endif | |||
| } | |||
| ok = es->triggered; | |||
| } | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| return ok; | |||
| } | |||
| void WaitableEvent::signal() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = true; | |||
| pthread_cond_broadcast (&es->condition); | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| void WaitableEvent::reset() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| //============================================================================== | |||
| void JUCE_CALLTYPE Thread::sleep (int millisecs) throw() | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = millisecs / 1000; | |||
| time.tv_nsec = (millisecs % 1000) * 1000000; | |||
| nanosleep (&time, 0); | |||
| } | |||
| //============================================================================== | |||
| const tchar File::separator = T('/'); | |||
| const tchar* File::separatorString = T("/"); | |||
| //============================================================================== | |||
| bool juce_copyFile (const String& s, const String& d) throw(); | |||
| static bool juce_stat (const String& fileName, struct stat& info) throw() | |||
| { | |||
| return fileName.isNotEmpty() | |||
| && (stat (fileName.toUTF8(), &info) == 0); | |||
| } | |||
| bool juce_isDirectory (const String& fileName) throw() | |||
| { | |||
| struct stat info; | |||
| return fileName.isEmpty() | |||
| || (juce_stat (fileName, info) | |||
| && ((info.st_mode & S_IFDIR) != 0)); | |||
| } | |||
| bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw() | |||
| { | |||
| if (fileName.isEmpty()) | |||
| return false; | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| bool exists = access (fileNameUTF8, F_OK) == 0; | |||
| if (exists && dontCountDirectories) | |||
| { | |||
| struct stat info; | |||
| const int res = stat (fileNameUTF8, &info); | |||
| if (res == 0 && (info.st_mode & S_IFDIR) != 0) | |||
| exists = false; | |||
| } | |||
| return exists; | |||
| } | |||
| int64 juce_getFileSize (const String& fileName) throw() | |||
| { | |||
| struct stat info; | |||
| return juce_stat (fileName, info) ? info.st_size : 0; | |||
| } | |||
| //============================================================================== | |||
| bool juce_canWriteToFile (const String& fileName) throw() | |||
| { | |||
| return access (fileName.toUTF8(), W_OK) == 0; | |||
| } | |||
| bool juce_deleteFile (const String& fileName) throw() | |||
| { | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| if (juce_isDirectory (fileName)) | |||
| return rmdir (fileNameUTF8) == 0; | |||
| else | |||
| return remove (fileNameUTF8) == 0; | |||
| } | |||
| bool juce_moveFile (const String& source, const String& dest) throw() | |||
| { | |||
| if (rename (source.toUTF8(), dest.toUTF8()) == 0) | |||
| return true; | |||
| if (juce_canWriteToFile (source) | |||
| && juce_copyFile (source, dest)) | |||
| { | |||
| if (juce_deleteFile (source)) | |||
| return true; | |||
| juce_deleteFile (dest); | |||
| } | |||
| return false; | |||
| } | |||
| void juce_createDirectory (const String& fileName) throw() | |||
| { | |||
| mkdir (fileName.toUTF8(), 0777); | |||
| } | |||
| void* juce_fileOpen (const String& fileName, bool forWriting) throw() | |||
| { | |||
| const char* const fileNameUTF8 = fileName.toUTF8(); | |||
| int flags = O_RDONLY; | |||
| if (forWriting) | |||
| { | |||
| if (juce_fileExists (fileName, false)) | |||
| { | |||
| const int f = open (fileNameUTF8, O_RDWR, 00644); | |||
| if (f != -1) | |||
| lseek (f, 0, SEEK_END); | |||
| return (void*) f; | |||
| } | |||
| else | |||
| { | |||
| flags = O_RDWR + O_CREAT; | |||
| } | |||
| } | |||
| return (void*) open (fileNameUTF8, flags, 00644); | |||
| } | |||
| void juce_fileClose (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| close ((int) handle); | |||
| } | |||
| int juce_fileRead (void* handle, void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return read ((int) handle, buffer, size); | |||
| return 0; | |||
| } | |||
| int juce_fileWrite (void* handle, const void* buffer, int size) throw() | |||
| { | |||
| if (handle != 0) | |||
| return write ((int) handle, buffer, size); | |||
| return 0; | |||
| } | |||
| int64 juce_fileSetPosition (void* handle, int64 pos) throw() | |||
| { | |||
| if (handle != 0 && lseek ((int) handle, pos, SEEK_SET) == pos) | |||
| return pos; | |||
| return -1; | |||
| } | |||
| int64 juce_fileGetPosition (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| return lseek ((int) handle, 0, SEEK_CUR); | |||
| else | |||
| return -1; | |||
| } | |||
| void juce_fileFlush (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| fsync ((int) handle); | |||
| } | |||
| //============================================================================== | |||
| // if this file doesn't exist, find a parent of it that does.. | |||
| static bool doStatFS (const File* file, struct statfs& result) throw() | |||
| { | |||
| File f (*file); | |||
| for (int i = 5; --i >= 0;) | |||
| { | |||
| if (f.exists()) | |||
| break; | |||
| f = f.getParentDirectory(); | |||
| } | |||
| return statfs (f.getFullPathName().toUTF8(), &result) == 0; | |||
| } | |||
| int64 File::getBytesFreeOnVolume() const throw() | |||
| { | |||
| int64 free_space = 0; | |||
| struct statfs buf; | |||
| if (doStatFS (this, buf)) | |||
| // Note: this returns space available to non-super user | |||
| free_space = (int64) buf.f_bsize * (int64) buf.f_bavail; | |||
| return free_space; | |||
| } | |||
| const String juce_getVolumeLabel (const String& filenameOnVolume, | |||
| int& volumeSerialNumber) throw() | |||
| { | |||
| // There is no equivalent on Linux | |||
| volumeSerialNumber = 0; | |||
| return String::empty; | |||
| } | |||
| //============================================================================== | |||
| #if JUCE_64BIT | |||
| #define filedesc ((long long) internal) | |||
| #else | |||
| #define filedesc ((int) internal) | |||
| #endif | |||
| InterProcessLock::InterProcessLock (const String& name_) throw() | |||
| : internal (0), | |||
| name (name_), | |||
| reentrancyLevel (0) | |||
| { | |||
| const File tempDir (File::getSpecialLocation (File::tempDirectory)); | |||
| const File temp (tempDir.getChildFile (name)); | |||
| temp.create(); | |||
| internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR); | |||
| } | |||
| InterProcessLock::~InterProcessLock() throw() | |||
| { | |||
| while (reentrancyLevel > 0) | |||
| this->exit(); | |||
| close (filedesc); | |||
| } | |||
| bool InterProcessLock::enter (const int timeOutMillisecs) throw() | |||
| { | |||
| if (internal == 0) | |||
| return false; | |||
| if (reentrancyLevel != 0) | |||
| return true; | |||
| const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
| struct flock fl; | |||
| zerostruct (fl); | |||
| fl.l_whence = SEEK_SET; | |||
| fl.l_type = F_WRLCK; | |||
| for (;;) | |||
| { | |||
| const int result = fcntl (filedesc, F_SETLK, &fl); | |||
| if (result >= 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| if (errno != EINTR) | |||
| { | |||
| if (timeOutMillisecs == 0 | |||
| || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime)) | |||
| break; | |||
| Thread::sleep (10); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void InterProcessLock::exit() throw() | |||
| { | |||
| if (reentrancyLevel > 0 && internal != 0) | |||
| { | |||
| --reentrancyLevel; | |||
| struct flock fl; | |||
| zerostruct (fl); | |||
| fl.l_whence = SEEK_SET; | |||
| fl.l_type = F_UNLCK; | |||
| for (;;) | |||
| { | |||
| const int result = fcntl (filedesc, F_SETLKW, &fl); | |||
| if (result >= 0 || errno != EINTR) | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @@ -23,7 +23,8 @@ Changelist for version 1.46 | |||
| - new method: PlatformUtilities::launchEmailWithAttachments | |||
| - new classes: AudioThumbnail and AudioThumbnailCache, which allow easy rendering of low-res waveform previews | |||
| - new classes: InputSource and FileInputSource. These encapsulate some kind of resource, and also replace the XmlInputSource class. | |||
| - moved some of the posix code that was the same in the mac and linux builds into a single, shared file | |||
| - fixed InterprocessLock on mac/linux so that it can't get stuck when an app quits unexpectedly | |||
| ============================================================================== | |||
| Changelist for version 1.45 | |||
| @@ -103,7 +103,7 @@ public: | |||
| bool moreThanOneInstanceAllowed() | |||
| { | |||
| return true; | |||
| return false; | |||
| } | |||
| void anotherInstanceStarted (const String& commandLine) | |||
| @@ -57,9 +57,9 @@ PluginDescription::PluginDescription (const PluginDescription& other) throw() | |||
| manufacturerName (other.manufacturerName), | |||
| version (other.version), | |||
| file (other.file), | |||
| lastFileModTime (other.lastFileModTime), | |||
| uid (other.uid), | |||
| isInstrument (other.isInstrument), | |||
| lastFileModTime (other.lastFileModTime), | |||
| numInputChannels (other.numInputChannels), | |||
| numOutputChannels (other.numOutputChannels) | |||
| { | |||