Windows arm64 support

Are there any plans to add ARM64 support for windows10 and the upcoming windows11? I tried building Projucer for ARM64 with msvc, but it got stuck on __cpuid and some other stuff that seems to exist only for x86/x64. I know I can run the x64 version of Projucer just fine, but ARM64 is only going to get bigger on windows and compared to rosetta2 on macOS the performance penalty is quite severe on windows.

Of course it’s too early for plugins, but being able to compile Windows/ARM64 apps would be very nice.

1 Like

Someone actually tried their hand at extending support for arm64. It’s in a very old PR in GitHub. Might be worth having a gander to see what’s needed.

1 Like

Thanks for letting me know. I thought about making a PR myself that then can rest on github to be never looked at again…

this the the old arm64 PR:

[First pass support for MSVC ARM64 by jwinarske · Pull Request #668 · juce-framework/JUCE · GitHub]

If I may suggest making this into smaller chunks. With cmake I’m pretty sure you can set basic arm64 settings and then first fix the actual core parts broken.

The PR above looks nice for just fixing those.

The PR I linked is too old to use as a patch, so I adapted some of the changes. It also has more changes than needed and I really don’t care about the SIMD classes at this point. With the following minimal .patch to juce 6.1.0 I was able to build Projucer for win|arm64 and then created a juce audio app with the Projucer that runs successfully and produces sound.

Of course this requires adding an “ARM64” config inside visual studio as Projucer can’t do that - and it’ll overwrite the config on each save. When starting the built .exe from visual studio there’s some illegal exception happening, but using “continue” makes the apps launch and when started regularly, things just work fine. Overall adding support to this seems easy, but the devil is probably in the details. I don’t care, I don’t need this for production yet, but if someone wants to take it further, here’s my minimal patch:

diff --git a/modules/juce_core/system/juce_TargetPlatform.h b/modules/juce_core/system/juce_TargetPlatform.h
index c21cff179278dab4ba570462280527de6d4b963f..67c2880586b7db407ca68124fad136b341ef8965 100644
--- a/modules/juce_core/system/juce_TargetPlatform.h
+++ b/modules/juce_core/system/juce_TargetPlatform.h
@@ -109,7 +109,11 @@
   /** If defined, this indicates that the processor is little-endian. */
-  #define JUCE_INTEL 1
+  #if defined(_M_ARM64)
+    #define JUCE_ARM 1
+  #elsea
+    #define JUCE_INTEL 1
+  #endif
diff --git a/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.7/lib/os.h b/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.7/lib/os.h
index fc65b594f81df0c7bff37191ed8ca3d0d3795884..8c55a4c84a6c9414b73c144b09569894f0b42fca 100644
--- a/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.7/lib/os.h
+++ b/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.7/lib/os.h
@@ -146,7 +146,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
 /* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be
    done safely because all x86_64 CPUs supports SSE2. */
-#if ((JUCE_MSVC && JUCE_64BIT) || (JUCE_GCC && defined (__x86_64__)))
+#if ((JUCE_MSVC && JUCE_64BIT && !defined(_M_ARM64)) || (JUCE_GCC && defined (__x86_64__)))
 typedef ogg_int16_t vorbis_fpu_control;
diff --git a/modules/juce_core/native/juce_win32_SystemStats.cpp b/modules/juce_core/native/juce_win32_SystemStats.cpp
index 2546db242973fc0ca73208c8f7e5d3d0cf816a81..512212f5a4195dbd37255a894e2f2237eac3aea3 100644
--- a/modules/juce_core/native/juce_win32_SystemStats.cpp
+++ b/modules/juce_core/native/juce_win32_SystemStats.cpp
@@ -23,7 +23,7 @@
 namespace juce
-#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
+#if JUCE_MSVC && ! defined (__INTEL_COMPILER) && !defined(_M_ARM64)
  #pragma intrinsic (__cpuid)
  #pragma intrinsic (__rdtsc)
@@ -62,7 +62,13 @@ static void callCPUID (int result[4], uint32 type)
 static void callCPUID (int result[4], int infoType)
-    __cpuid (result, infoType);
+#if defined(_M_ARM64)
+    ignoreUnused(infoType);
+    std::fill(result, result + 4, 0);
+    __cpuid(result, infoType);
@@ -438,7 +444,11 @@ static int64 juce_getClockCycleCounter() noexcept
    #if JUCE_MSVC
     // MS intrinsics version...
-    return (int64) __rdtsc();
+   #if defined(_M_ARM64)
+      return _ReadStatusReg(ARM64_PMCCNTR_EL0);
+   #else
+      return (int64)__rdtsc();
+   #endif
    #elif JUCE_GCC || JUCE_CLANG
     // GNU inline asm version...