From 35e0c0017a7f4784724c36fadfd7ae810ec080e5 Mon Sep 17 00:00:00 2001
From: Gerasim Troeglazov <3dEyes@gmail.com>
Date: Sat, 4 Sep 2021 19:15:09 +1000
Subject: Add Haiku support


diff --git a/CMakeLists.txt b/CMakeLists.txt
index bec38eb..f30e0c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -241,7 +241,7 @@ if(APPLE)
 endif()
 
 # ALSA (Linux only)
-if(UNIX AND NOT APPLE)
+if(UNIX AND NOT APPLE AND NOT HAIKU)
   set(NEED_ALSA TRUE)
   find_package(ALSA REQUIRED)
   if (ALSA_FOUND AND NOT TARGET ALSA::ALSA) # CMake < 3.12
@@ -257,6 +257,11 @@ else()
   set(NEED_ALSA FALSE)
 endif()
 
+# Haiku
+if(HAIKU)
+  target_link_libraries(openshot-audio PUBLIC network media)
+endif()
+
 # ZLIB -- uses IMPORTED target ZLIB::ZLIB which has existed since CMake 3.1
 find_package(ZLIB REQUIRED)
 target_link_libraries(openshot-audio PUBLIC ZLIB::ZLIB)
diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
index 3e120f0..6ec4c59 100644
--- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
+++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
@@ -175,6 +175,7 @@ void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>&
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela());
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());
+    addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Haiku());
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe());
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES());
     addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android());
diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp
index fa67206..de37b92 100644
--- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp
+++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.cpp
@@ -70,6 +70,10 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_ALSA()
 AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK()            { return nullptr; }
 #endif
 
+#if ! (JUCE_HAIKU)
+AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Haiku()           { return nullptr; }
+#endif
+
 #if ! (JUCE_LINUX && JUCE_BELA)
 AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Bela()            { return nullptr; }
 #endif
diff --git a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
index 1aa1a67..320fe29 100644
--- a/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
+++ b/JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h
@@ -159,6 +159,8 @@ public:
     static AudioIODeviceType* createAudioIODeviceType_ALSA();
     /** Creates a JACK device type if it's available on this platform, or returns null. */
     static AudioIODeviceType* createAudioIODeviceType_JACK();
+    /** Creates a Haiku device type if it's available on this platform, or returns null. */
+    static AudioIODeviceType* createAudioIODeviceType_Haiku();
     /** Creates an Android device type if it's available on this platform, or returns null. */
     static AudioIODeviceType* createAudioIODeviceType_Android();
     /** Creates an Android OpenSLES device type if it's available on this platform, or returns null. */
diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp
index e59d80a..8529e30 100644
--- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp
+++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.cpp
@@ -238,6 +238,16 @@
  #if JUCE_USE_ANDROID_OBOE
   #include "native/juce_android_Oboe.cpp"
  #endif
+
+//==============================================================================
+#elif JUCE_HAIKU
+ #include "native/juce_haiku_Midi.cpp"
+ #include "native/juce_haiku_Audio.cpp"
+
+ #if JUCE_USE_CDREADER
+  #include "native/juce_linux_AudioCDReader.cpp"
+ #endif
+
 #endif
 
 #if ! JUCE_SYSTEMAUDIOVOL_IMPLEMENTED
diff --git a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h
index 2027b77..a6021b6 100644
--- a/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h
+++ b/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h
@@ -115,7 +115,7 @@
     Enables ALSA audio devices (Linux only).
 */
 #ifndef JUCE_ALSA
- #define JUCE_ALSA 1
+ #define JUCE_ALSA 0
 #endif
 
 /** Config: JUCE_JACK
diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Audio.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Audio.cpp
new file mode 100644
index 0000000..9b28650
--- /dev/null
+++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Audio.cpp
@@ -0,0 +1,291 @@
+/* Haiku audio output module for JUCE library.
+(c) 2018 Gerasim Troeglazov (3dEyes**)*/
+
+#define BUFFER_SIZE 		1024
+#define AUDIO_TYPE			int16
+#define AUDIO_RATE			44100
+#define AUDIO_IN_CHANNELS	1
+#define AUDIO_OUT_CHANNELS	2
+#define AUDIO_BYTES			sizeof(AUDIO_TYPE)
+#define AUDIO_BITS			(AUDIO_BYTES * 8)
+
+#include <MediaKit.h>
+
+namespace juce
+{
+
+const char* const haikuAudioTypeName = "MediaKit Audio";
+
+class HaikuAudioIODevice  : public AudioIODevice
+{
+public:
+	HaikuAudioIODevice(const String& deviceName)
+		: AudioIODevice(deviceName, haikuAudioTypeName),
+		soundPlayer(NULL),
+		callback(nullptr),
+		inputChannelBuffer(1, 1),
+		outputChannelBuffer(1, 1)
+	{
+	}
+
+	~HaikuAudioIODevice()
+	{
+		close();
+	}
+
+	StringArray getOutputChannelNames() override
+	{
+		StringArray s;
+		s.add("Left");
+		s.add("Right");
+		return s;
+	}
+
+	StringArray getInputChannelNames() override
+	{
+		StringArray s;
+		return s;
+	}
+
+	Array<double> getAvailableSampleRates() override
+	{
+		Array<double> r;
+		r.add((double)AUDIO_RATE);
+		return r;
+	}
+
+	Array<int> getAvailableBufferSizes() override
+	{
+		Array<int> b;
+		b.add(BUFFER_SIZE);
+		return b;
+	}
+
+    int getDefaultBufferSize() override
+    {
+		return BUFFER_SIZE;
+	}
+
+	String open(const BigInteger& inputChannels,
+		const BigInteger& outputChannels,
+		double requestedSampleRate,
+		int bufferSize) override
+	{
+		close();
+
+		if ((int) requestedSampleRate != AUDIO_RATE)
+			return "Sample rate not allowed";
+
+		lastError.clear();
+
+		media_raw_audio_format mediaKitFormat = {
+			(float)AUDIO_RATE,
+			(uint32)AUDIO_OUT_CHANNELS,
+			media_raw_audio_format::B_AUDIO_SHORT,
+			B_MEDIA_LITTLE_ENDIAN,
+			(uint32)BUFFER_SIZE * AUDIO_OUT_CHANNELS * AUDIO_BYTES
+		};
+
+		inputChannelBuffer.setSize (AUDIO_IN_CHANNELS, BUFFER_SIZE);
+		inputChannelBuffer.clear();
+		outputChannelBuffer.setSize (AUDIO_OUT_CHANNELS, BUFFER_SIZE);
+		outputChannelBuffer.clear();
+
+		soundPlayer = new BSoundPlayer(&mediaKitFormat, "OpenShot", \
+			processCallback, NULL, (void*)this);
+
+		if (soundPlayer->InitCheck() != B_OK) {
+			delete soundPlayer;
+			soundPlayer = nullptr;
+			lastError = "BSoundPlayer not initialized";
+		}
+
+		return lastError;
+	}
+
+	void close() override
+	{
+		if (soundPlayer != nullptr) {
+			soundPlayer->SetHasData(false);
+			soundPlayer->Stop();
+			delete soundPlayer;
+			soundPlayer = nullptr;
+		}
+	}
+
+	int getOutputLatencyInSamples() override
+	{
+		return 0;
+	}
+	
+	int getInputLatencyInSamples() override
+	{
+		return 0;
+	}
+
+	bool isOpen() override
+	{
+		if (soundPlayer == nullptr)
+			return false;
+		if (soundPlayer->InitCheck() != B_OK)
+			return false;
+		return true;
+	}
+
+	int getCurrentBufferSizeSamples() override
+	{
+		return BUFFER_SIZE;
+	}
+    
+	int getCurrentBitDepth() override
+	{
+		return AUDIO_BITS;
+	}
+	
+	double getCurrentSampleRate() override
+	{
+		return AUDIO_RATE;
+	}
+
+	BigInteger getActiveOutputChannels() const override
+	{
+		return AUDIO_OUT_CHANNELS;
+	}
+	
+	BigInteger getActiveInputChannels() const override
+	{
+		return AUDIO_IN_CHANNELS;
+	}
+	
+	String getLastError() override
+	{
+		return lastError;
+	}
+
+	bool isPlaying() override
+	{
+		if (soundPlayer == nullptr)
+			return false;
+		return soundPlayer->HasData();
+	}
+
+	void start(AudioIODeviceCallback* newCallback) override
+	{
+		if (soundPlayer != nullptr && callback != newCallback) {
+			if (newCallback != nullptr)newCallback->audioDeviceAboutToStart (this);
+			const ScopedLock sl (callbackLock);
+			callback = newCallback;
+		}
+		soundPlayer->Start();
+		soundPlayer->SetHasData(true);
+	}
+
+	void stop() override
+	{
+		soundPlayer->SetHasData(false);
+		soundPlayer->Stop();
+
+		outputChannelBuffer.clear();
+
+		if (soundPlayer != nullptr) {
+			AudioIODeviceCallback* lastCallback;
+            {
+				const ScopedLock sl (callbackLock);
+				lastCallback = callback;
+				callback = nullptr;
+			}
+			if (lastCallback != nullptr)
+				lastCallback->audioDeviceStopped();
+		}
+	}
+
+private:
+	void process (void *buffer, size_t len)
+	{
+		int16 *destBuffer = (int16*)buffer;
+		size_t numSamples = len / (AUDIO_OUT_CHANNELS * AUDIO_BYTES);
+		{
+			const ScopedLock sl (callbackLock);
+			if (callback != nullptr) {
+				callback->audioDeviceIOCallback (inputChannelBuffer.getArrayOfReadPointers(), AUDIO_IN_CHANNELS,
+					outputChannelBuffer.getArrayOfWritePointers(), AUDIO_OUT_CHANNELS, numSamples);
+			} else {
+				outputChannelBuffer.clear();
+			}
+		}
+		for (int i = 0; i < AUDIO_OUT_CHANNELS; ++i) {
+			typedef AudioData::Pointer <AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
+			typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
+			DstSampleType dstData (destBuffer + i, AUDIO_OUT_CHANNELS);
+			SrcSampleType srcData (outputChannelBuffer.getReadPointer (i, 0));
+			dstData.convertSamples (srcData, numSamples);
+		}
+	}
+
+	static void processCallback(void *cookie, void *buffer, size_t len, const media_raw_audio_format &format)
+	{
+		if (cookie != nullptr)
+			((HaikuAudioIODevice*) cookie)->process (buffer, len);
+		else
+			zeromem(buffer, len);
+	}
+	
+    AudioSampleBuffer inputChannelBuffer, outputChannelBuffer;
+	String lastError;
+	AudioIODeviceCallback* callback;
+	CriticalSection callbackLock;
+	BSoundPlayer *soundPlayer;
+
+	JUCE_DECLARE_NON_COPYABLE (HaikuAudioIODevice)
+};
+
+
+class HaikuAudioIODeviceType  : public AudioIODeviceType
+{
+public:
+	HaikuAudioIODeviceType() : AudioIODeviceType (haikuAudioTypeName) {}
+
+	void scanForDevices() {}
+
+	StringArray getDeviceNames (bool wantInputNames) const
+	{
+		return StringArray (haikuAudioTypeName);
+	}
+    
+	int getDefaultDeviceIndex (bool forInput) const
+	{
+		return 0;
+	}
+
+	int getIndexOfDevice (AudioIODevice* device, bool asInput) const
+	{
+		return (device != nullptr && !asInput) ? 0 : -1;
+	}
+	
+	bool hasSeparateInputsAndOutputs() const
+	{
+		return true;
+	}
+
+	AudioIODevice* createDevice (const String& outputDeviceName, const String& inputDeviceName)
+	{
+		ScopedPointer<HaikuAudioIODevice> dev;
+        if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty()) {
+			dev = new HaikuAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName : inputDeviceName);
+			if (dev->getCurrentSampleRate() <= 0 || dev->getDefaultBufferSize() <= 0)
+				dev = nullptr;
+		}
+		return dev.release();
+	}
+
+private:
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HaikuAudioIODeviceType)
+};
+
+
+AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_Haiku()
+{
+	return new HaikuAudioIODeviceType();
+}
+
+} // namespace juce
diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Midi.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Midi.cpp
new file mode 100644
index 0000000..466b926
--- /dev/null
+++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_haiku_Midi.cpp
@@ -0,0 +1,53 @@
+/*
+  ==============================================================================
+
+   This file is part of the JUCE library.
+   Copyright (c) 2017 - ROLI Ltd.
+
+   JUCE is an open source library subject to commercial or open-source
+   licensing.
+
+   The code included in this file is provided under the terms of the ISC license
+   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+   To use, copy, modify, and/or distribute this software for any purpose with or
+   without fee is hereby granted provided that the above copyright notice and
+   this permission notice appear in all copies.
+
+   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+   DISCLAIMED.
+
+  ==============================================================================
+*/
+
+namespace juce
+{
+
+// (These are just stub functions if ALSA is unavailable...)
+MidiInput::MidiInput (const String& deviceName, const String& deviceID)
+    : deviceInfo (deviceName, deviceID)
+{
+}
+
+MidiInput::~MidiInput()                                                                   {}
+void MidiInput::start()                                                                   {}
+void MidiInput::stop()                                                                    {}
+Array<MidiDeviceInfo> MidiInput::getAvailableDevices()                                    { return {}; }
+MidiDeviceInfo MidiInput::getDefaultDevice()                                              { return {}; }
+std::unique_ptr<MidiInput> MidiInput::openDevice (const String&, MidiInputCallback*)      { return {}; }
+//std::unique_ptr<MidiInput> MidiInput::createNewDevice (const String&, MidiInputCallback*) { return {}; }
+StringArray MidiInput::getDevices()                                                       { return {}; }
+int MidiInput::getDefaultDeviceIndex()                                                    { return 0;}
+std::unique_ptr<MidiInput> MidiInput::openDevice (int, MidiInputCallback*)                { return {}; }
+
+MidiOutput::~MidiOutput()                                                                 {}
+void MidiOutput::sendMessageNow (const MidiMessage&)                                      {}
+Array<MidiDeviceInfo> MidiOutput::getAvailableDevices()                                   { return {}; }
+MidiDeviceInfo MidiOutput::getDefaultDevice()                                             { return {}; }
+std::unique_ptr<MidiOutput> MidiOutput::openDevice (const String&)                        { return {}; }
+//std::unique_ptr<MidiOutput> MidiOutput::createNewDevice (const String&)                   { return {}; }
+StringArray MidiOutput::getDevices()                                                      { return {}; }
+int MidiOutput::getDefaultDeviceIndex()                                                   { return 0;}
+std::unique_ptr<MidiOutput> MidiOutput::openDevice (int)                                  { return {}; }
+
+} // namespace juce
diff --git a/JuceLibraryCode/modules/juce_core/juce_core.cpp b/JuceLibraryCode/modules/juce_core/juce_core.cpp
index 8bac812..f492815 100644
--- a/JuceLibraryCode/modules/juce_core/juce_core.cpp
+++ b/JuceLibraryCode/modules/juce_core/juce_core.cpp
@@ -92,7 +92,7 @@
  #include <net/if.h>
  #include <sys/ioctl.h>
 
- #if ! JUCE_ANDROID
+ #if ! JUCE_ANDROID && ! JUCE_HAIKU
   #include <execinfo.h>
  #endif
 #endif
@@ -207,7 +207,7 @@
  #include "native/juce_win32_Threads.cpp"
 
 //==============================================================================
-#elif JUCE_LINUX
+#elif JUCE_LINUX || JUCE_HAIKU
  #include "native/juce_linux_CommonFile.cpp"
  #include "native/juce_linux_Files.cpp"
  #include "native/juce_linux_Network.cpp"
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h b/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h
index 900933c..319e2d0 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h
+++ b/JuceLibraryCode/modules/juce_core/native/juce_BasicNativeHeaders.h
@@ -273,6 +273,35 @@
  #include <utime.h>
  #include <poll.h>
 
+//==============================================================================
+#elif JUCE_HAIKU
+ #include <string.h>
+ #include <arpa/inet.h>
+ #include <dirent.h>
+ #include <dlfcn.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <fnmatch.h>
+ #include <net/if.h>
+ #include <netdb.h>
+ #include <netinet/in.h>
+ #include <pthread.h>
+ #include <pwd.h>
+ #include <sched.h>
+ #include <signal.h>
+ #include <stddef.h>
+ #include <sys/file.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <sys/statvfs.h>
+ #include <utime.h>
+ #include <poll.h>
+ 
 //==============================================================================
 #elif JUCE_ANDROID
  #include <jni.h>
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp
index 082a535..317ceea 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp
+++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_Files.cpp
@@ -33,14 +33,19 @@ enum
 
 bool File::isOnCDRomDrive() const
 {
+	#if JUCE_HAIKU
+	return false;
+	#else
     struct statfs buf;
 
     return statfs (getFullPathName().toUTF8(), &buf) == 0
              && buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
+	#endif
 }
 
 bool File::isOnHardDisk() const
 {
+	#if ! JUCE_HAIKU
     struct statfs buf;
 
     if (statfs (getFullPathName().toUTF8(), &buf) == 0)
@@ -56,6 +61,7 @@ bool File::isOnHardDisk() const
             default: break;
         }
     }
+    #endif
 
     // Assume so if this fails for some reason
     return true;
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp
index 5b7c846..f9b4ab8 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp
+++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_Network.cpp
@@ -25,6 +25,7 @@ namespace juce
 
 void MACAddress::findAllAddresses (Array<MACAddress>& result)
 {
+#if !JUCE_HAIKU
     auto s = socket (AF_INET, SOCK_DGRAM, 0);
 
     if (s != -1)
@@ -53,6 +54,7 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
 
         ::close (s);
     }
+#endif
 }
 
 
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp
index 2d7faa3..935d0b3 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp
+++ b/JuceLibraryCode/modules/juce_core/native/juce_linux_SystemStats.cpp
@@ -20,6 +20,9 @@
   ==============================================================================
 */
 
+#include <nl_types.h>
+#include <langinfo.h>
+
 #if JUCE_BELA
 extern "C" int cobalt_thread_mode();
 #endif
@@ -91,11 +94,12 @@ int SystemStats::getCpuSpeedInMegahertz()
 
 int SystemStats::getMemorySizeInMegabytes()
 {
+	#if ! JUCE_HAIKU
     struct sysinfo sysi;
 
     if (sysinfo (&sysi) == 0)
         return (int) (sysi.totalram * sysi.mem_unit / (1024 * 1024));
-
+	#endif
     return 0;
 }
 
@@ -139,8 +143,8 @@ static String getLocaleValue (nl_item key)
     return result;
 }
 
-String SystemStats::getUserLanguage()     { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
-String SystemStats::getUserRegion()       { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
+String SystemStats::getUserLanguage()     { return getLocaleValue (0); }
+String SystemStats::getUserRegion()       { return getLocaleValue (0); }
 String SystemStats::getDisplayLanguage()  { return getUserLanguage() + "-" + getUserRegion(); }
 
 //==============================================================================
@@ -214,11 +218,12 @@ double Time::getMillisecondCounterHiRes() noexcept
 
 bool Time::setSystemTimeToThisTime() const
 {
-    timeval t;
+/*    timeval t;
     t.tv_sec = millisSinceEpoch / 1000;
     t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
 
-    return settimeofday (&t, nullptr) == 0;
+    return settimeofday (&t, nullptr) == 0;*/
+    return false;
 }
 
 JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h b/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h
index b72d5c3..78c9910 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h
+++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_IPAddress.h
@@ -67,6 +67,7 @@ namespace
 
     bool populateInterfaceInfo (struct ifaddrs* ifa, InterfaceInfo& interfaceInfo)
     {
+		#if ! JUCE_HAIKU
         if (ifa->ifa_addr != nullptr)
         {
             if (ifa->ifa_addr->sa_family == AF_INET)
@@ -88,7 +89,7 @@ namespace
                 return true;
             }
         }
-
+		#endif
         return false;
     }
 
@@ -96,7 +97,7 @@ namespace
     {
         Array<InterfaceInfo> interfaces;
         struct ifaddrs* ifaddr = nullptr;
-
+		#if ! JUCE_HAIKU
         if (getifaddrs (&ifaddr) != -1)
         {
             for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
@@ -109,7 +110,7 @@ namespace
 
             freeifaddrs (ifaddr);
         }
-
+		#endif
         return interfaces;
     }
 }
diff --git a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h
index 664727d..15d5ef7 100644
--- a/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h
+++ b/JuceLibraryCode/modules/juce_core/native/juce_posix_SharedCode.h
@@ -169,7 +169,7 @@ namespace
     }
 
     // if this file doesn't exist, find a parent of it that does..
-    bool juce_doStatFS (File f, struct statfs& result)
+    bool juce_doStatFS (File f, struct statvfs& result)
     {
         for (int i = 5; --i >= 0;)
         {
@@ -178,8 +178,11 @@ namespace
 
             f = f.getParentDirectory();
         }
-
+		#if JUCE_HAIKU
+		return statvfs (f.getFullPathName().toUTF8(), &result) == 0;
+		#else
         return statfs (f.getFullPathName().toUTF8(), &result) == 0;
+        #endif
     }
 
    #if JUCE_MAC || JUCE_IOS
@@ -597,7 +600,7 @@ File juce_getExecutableFile()
 //==============================================================================
 int64 File::getBytesFreeOnVolume() const
 {
-    struct statfs buf;
+    struct statvfs buf;
 
     if (juce_doStatFS (*this, buf))
         return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
@@ -607,7 +610,7 @@ int64 File::getBytesFreeOnVolume() const
 
 int64 File::getVolumeTotalSize() const
 {
-    struct statfs buf;
+    struct statvfs buf;
 
     if (juce_doStatFS (*this, buf))
         return (int64) buf.f_bsize * (int64) buf.f_blocks;
@@ -680,7 +683,7 @@ String juce_getOutputFromCommand (const String& command)
 #endif
 
 //==============================================================================
-#if JUCE_IOS
+#if JUCE_IOS || JUCE_HAIKU
 class InterProcessLock::Pimpl
 {
 public:
diff --git a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp
index 757ea24..c3e782a 100644
--- a/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp
+++ b/JuceLibraryCode/modules/juce_core/system/juce_SystemStats.cpp
@@ -138,7 +138,7 @@ String SystemStats::getStackBacktrace()
 {
     String result;
 
-   #if JUCE_ANDROID || JUCE_MINGW
+   #if JUCE_ANDROID || JUCE_MINGW || JUCE_HAIKU
     jassertfalse; // sorry, not implemented yet!
 
    #elif JUCE_WINDOWS
diff --git a/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h b/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h
index 4d6ba10..730e8a5 100644
--- a/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h
+++ b/JuceLibraryCode/modules/juce_core/system/juce_TargetPlatform.h
@@ -65,6 +65,8 @@
   #define       JUCE_ANDROID 1
 #elif defined (__FreeBSD__) || (__OpenBSD__)
   #define       JUCE_BSD 1
+#elif defined (__HAIKU__)
+  #define       JUCE_HAIKU 1
 #elif defined (LINUX) || defined (__linux__)
   #define     JUCE_LINUX 1
 #elif defined (__APPLE_CPP__) || defined (__APPLE_CC__)
@@ -152,7 +154,7 @@
 #endif
 
 //==============================================================================
-#if JUCE_LINUX || JUCE_ANDROID
+#if JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU
 
   #ifdef _DEBUG
     #define JUCE_DEBUG 1
diff --git a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h
index 516028f..035774b 100644
--- a/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h
+++ b/JuceLibraryCode/modules/juce_core/text/juce_CharacterFunctions.h
@@ -394,6 +394,8 @@ public:
        #if JUCE_WINDOWS
         static _locale_t locale = _create_locale (LC_ALL, "C");
         return _strtod_l (&buffer[0], nullptr, locale);
+       #elif JUCE_HAIKU
+        return strtod(&buffer[0], nullptr);
        #else
         static locale_t locale = newlocale (LC_ALL_MASK, "C", nullptr);
         #if JUCE_ANDROID
diff --git a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
index c729a70..e9703b5 100644
--- a/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
+++ b/JuceLibraryCode/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
@@ -90,7 +90,7 @@ File PropertiesFile::Options::getDefaultFile() const
     if (folderName.isNotEmpty())
         dir = dir.getChildFile (folderName);
 
-   #elif JUCE_LINUX || JUCE_ANDROID
+   #elif JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU
     auto dir = File (commonToAllUsers ? "/var" : "~")
                       .getChildFile (folderName.isNotEmpty() ? folderName
                                                              : ("." + applicationName));
diff --git a/JuceLibraryCode/modules/juce_events/juce_events.cpp b/JuceLibraryCode/modules/juce_events/juce_events.cpp
index e19d6d8..242a531 100644
--- a/JuceLibraryCode/modules/juce_events/juce_events.cpp
+++ b/JuceLibraryCode/modules/juce_events/juce_events.cpp
@@ -97,6 +97,9 @@
 #elif JUCE_LINUX
  #include "native/juce_linux_Messaging.cpp"
 
+#elif JUCE_HAIKU
+ #include "native/juce_haiku_Messaging.cpp"
+
 #elif JUCE_ANDROID
  #include "native/juce_android_Messaging.cpp"
 
diff --git a/JuceLibraryCode/modules/juce_events/juce_events.h b/JuceLibraryCode/modules/juce_events/juce_events.h
index 623a78d..a24e3a1 100644
--- a/JuceLibraryCode/modules/juce_events/juce_events.h
+++ b/JuceLibraryCode/modules/juce_events/juce_events.h
@@ -94,6 +94,10 @@
  #include "native/juce_linux_EventLoop.h"
 #endif
 
+#if JUCE_HAIKU
+ #include "native/juce_haiku_EventLoop.h"
+#endif
+
 #if JUCE_WINDOWS
  #if JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW
   #include "native/juce_win32_HiddenMessageWindow.h"
diff --git a/JuceLibraryCode/modules/juce_events/native/juce_haiku_EventLoop.h b/JuceLibraryCode/modules/juce_events/native/juce_haiku_EventLoop.h
new file mode 100644
index 0000000..ee6c898
--- /dev/null
+++ b/JuceLibraryCode/modules/juce_events/native/juce_haiku_EventLoop.h
@@ -0,0 +1,50 @@
+/*
+  ==============================================================================
+
+   This file is part of the JUCE library.
+   Copyright (c) 2017 - ROLI Ltd.
+
+   JUCE is an open source library subject to commercial or open-source
+   licensing.
+
+   The code included in this file is provided under the terms of the ISC license
+   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+   To use, copy, modify, and/or distribute this software for any purpose with or
+   without fee is hereby granted provided that the above copyright notice and
+   this permission notice appear in all copies.
+
+   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+   DISCLAIMED.
+
+  ==============================================================================
+*/
+
+namespace juce
+{
+
+namespace LinuxEventLoop
+{
+    /** Registers a callback that will be called when a file descriptor is ready for I/O.
+
+        This will add the given file descriptor to the internal set of file descriptors
+        that will be passed to the poll() call. When this file descriptor has data to read
+        the readCallback will be called.
+
+        @param fd            the file descriptor to be monitored
+        @param readCallback  a callback that will be called when the file descriptor has
+                             data to read. The file descriptor will be passed as an argument
+        @param eventMask     a bit mask specifying the events you are interested in for the
+                             file descriptor. The possible values for this are defined in
+                             <poll.h>
+    */
+    void registerFdCallback (int fd, std::function<void(int)> readCallback, short eventMask = 1 /*POLLIN*/);
+
+    /** Unregisters a previously registered file descriptor.
+
+        @see registerFdCallback
+    */
+    void unregisterFdCallback (int fd);
+}
+
+} // namespace juce
diff --git a/JuceLibraryCode/modules/juce_events/native/juce_haiku_Messaging.cpp b/JuceLibraryCode/modules/juce_events/native/juce_haiku_Messaging.cpp
new file mode 100644
index 0000000..b24016d
--- /dev/null
+++ b/JuceLibraryCode/modules/juce_events/native/juce_haiku_Messaging.cpp
@@ -0,0 +1,286 @@
+/*
+  ==============================================================================
+
+   This file is part of the JUCE library.
+   Copyright (c) 2017 - ROLI Ltd.
+
+   JUCE is an open source library subject to commercial or open-source
+   licensing.
+
+   The code included in this file is provided under the terms of the ISC license
+   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+   To use, copy, modify, and/or distribute this software for any purpose with or
+   without fee is hereby granted provided that the above copyright notice and
+   this permission notice appear in all copies.
+
+   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+   DISCLAIMED.
+
+  ==============================================================================
+*/
+
+namespace juce
+{
+
+//==============================================================================
+class InternalMessageQueue
+{
+public:
+    InternalMessageQueue()
+    {
+        auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe);
+        jassert (err == 0);
+        ignoreUnused (err);
+
+        LinuxEventLoop::registerFdCallback (getReadHandle(),
+                                            [this] (int fd)
+                                            {
+                                                while (auto msg = popNextMessage (fd))
+                                                {
+                                                    JUCE_TRY
+                                                    {
+                                                        msg->messageCallback();
+                                                    }
+                                                    JUCE_CATCH_EXCEPTION
+                                                }
+                                            });
+    }
+
+    ~InternalMessageQueue()
+    {
+        LinuxEventLoop::unregisterFdCallback (getReadHandle());
+
+        close (getReadHandle());
+        close (getWriteHandle());
+
+        clearSingletonInstance();
+    }
+
+    //==============================================================================
+    void postMessage (MessageManager::MessageBase* const msg) noexcept
+    {
+        ScopedLock sl (lock);
+        queue.add (msg);
+
+        if (bytesInSocket < maxBytesInSocketQueue)
+        {
+            bytesInSocket++;
+
+            ScopedUnlock ul (lock);
+            unsigned char x = 0xff;
+            auto numBytes = write (getWriteHandle(), &x, 1);
+            ignoreUnused (numBytes);
+        }
+    }
+
+    //==============================================================================
+    JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
+
+private:
+    CriticalSection lock;
+    ReferenceCountedArray <MessageManager::MessageBase> queue;
+
+    int msgpipe[2];
+    int bytesInSocket = 0;
+    static constexpr int maxBytesInSocketQueue = 128;
+
+    int getWriteHandle() const noexcept  { return msgpipe[0]; }
+    int getReadHandle() const noexcept   { return msgpipe[1]; }
+
+    MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
+    {
+        const ScopedLock sl (lock);
+
+        if (bytesInSocket > 0)
+        {
+            --bytesInSocket;
+
+            ScopedUnlock ul (lock);
+            unsigned char x;
+            auto numBytes = read (fd, &x, 1);
+            ignoreUnused (numBytes);
+        }
+
+        return queue.removeAndReturn (0);
+    }
+};
+
+JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
+
+//==============================================================================
+struct InternalRunLoop
+{
+public:
+    InternalRunLoop()
+    {
+        fdReadCallbacks.reserve (8);
+    }
+
+    void registerFdCallback (int fd, std::function<void(int)>&& cb, short eventMask)
+    {
+        const ScopedLock sl (lock);
+
+        fdReadCallbacks.push_back ({ fd, std::move (cb) });
+        pfds.push_back ({ fd, eventMask, 0 });
+    }
+
+    void unregisterFdCallback (int fd)
+    {
+        const ScopedLock sl (lock);
+
+        {
+            auto removePredicate = [=] (const std::pair<int, std::function<void(int)>>& cb)  { return cb.first == fd; };
+
+            fdReadCallbacks.erase (std::remove_if (std::begin (fdReadCallbacks), std::end (fdReadCallbacks), removePredicate),
+                                   std::end (fdReadCallbacks));
+        }
+
+        {
+            auto removePredicate = [=] (const pollfd& pfd)  { return pfd.fd == fd; };
+
+            pfds.erase (std::remove_if (std::begin (pfds), std::end (pfds), removePredicate),
+                        std::end (pfds));
+        }
+    }
+
+    bool dispatchPendingEvents()
+    {
+        const ScopedLock sl (lock);
+
+        if (poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), 0) == 0)
+            return false;
+
+        bool eventWasSent = false;
+
+        for (auto& pfd : pfds)
+        {
+            if (pfd.revents == 0)
+                continue;
+
+            pfd.revents = 0;
+
+            auto fd = pfd.fd;
+
+            for (auto& fdAndCallback : fdReadCallbacks)
+            {
+                if (fdAndCallback.first == fd)
+                {
+                    fdAndCallback.second (fd);
+                    eventWasSent = true;
+                }
+            }
+        }
+
+        return eventWasSent;
+    }
+
+    void sleepUntilNextEvent (int timeoutMs)
+    {
+        poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), timeoutMs);
+    }
+
+    //==============================================================================
+    JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
+
+private:
+    CriticalSection lock;
+
+    std::vector<std::pair<int, std::function<void(int)>>> fdReadCallbacks;
+    std::vector<pollfd> pfds;
+};
+
+JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
+
+//==============================================================================
+namespace LinuxErrorHandling
+{
+    static bool keyboardBreakOccurred = false;
+
+    void keyboardBreakSignalHandler (int sig)
+    {
+        if (sig == SIGINT)
+            keyboardBreakOccurred = true;
+    }
+
+    void installKeyboardBreakHandler()
+    {
+        struct sigaction saction;
+        sigset_t maskSet;
+        sigemptyset (&maskSet);
+        saction.sa_handler = keyboardBreakSignalHandler;
+        saction.sa_mask = maskSet;
+        saction.sa_flags = 0;
+        sigaction (SIGINT, &saction, nullptr);
+    }
+}
+
+//==============================================================================
+void MessageManager::doPlatformSpecificInitialisation()
+{
+    if (JUCEApplicationBase::isStandaloneApp())
+        LinuxErrorHandling::installKeyboardBreakHandler();
+
+    InternalRunLoop::getInstance();
+    InternalMessageQueue::getInstance();
+}
+
+void MessageManager::doPlatformSpecificShutdown()
+{
+    InternalMessageQueue::deleteInstance();
+    InternalRunLoop::deleteInstance();
+}
+
+bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
+{
+    if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
+    {
+        queue->postMessage (message);
+        return true;
+    }
+
+    return false;
+}
+
+void MessageManager::broadcastMessage (const String&)
+{
+    // TODO
+}
+
+// this function expects that it will NEVER be called simultaneously for two concurrent threads
+bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
+{
+    for (;;)
+    {
+        if (LinuxErrorHandling::keyboardBreakOccurred)
+            JUCEApplicationBase::quit();
+
+        if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
+        {
+            if (runLoop->dispatchPendingEvents())
+                break;
+
+            if (returnIfNoPendingMessages)
+                return false;
+
+            runLoop->sleepUntilNextEvent (2000);
+        }
+    }
+
+    return true;
+}
+
+//==============================================================================
+void LinuxEventLoop::registerFdCallback (int fd, std::function<void(int)> readCallback, short eventMask)
+{
+    if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
+        runLoop->registerFdCallback (fd, std::move (readCallback), eventMask);
+}
+
+void LinuxEventLoop::unregisterFdCallback (int fd)
+{
+    if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
+        runLoop->unregisterFdCallback (fd);
+}
+
+} // namespace juce
-- 
2.30.2

