Skip to content

Commit 175e6b1

Browse files
committed
Initial Import
0 parents  commit 175e6b1

31 files changed

Lines changed: 8124 additions & 0 deletions

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
build/
2+
.DS_Store
3+
*~
4+
ndisdk/
5+
3rdparty/macos/*SDK*
6+
3rdparty/windows/*SDK*

3rdparty/macos/README.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Place the Adobe SDKs in this directory. See the "Building from source"
2+
section of README.md for download links and setup instructions.

3rdparty/windows/README.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Place the Adobe SDKs in this directory. See the "Building from source"
2+
section of README.md for download links and setup instructions.

LICENSE.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
BSD 2-Clause License
2+
3+
Copyright (c) 2026 Kevin Day
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Makefile

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Platform detection
2+
ifeq ($(OS),Windows_NT)
3+
PLATFORM := windows
4+
else
5+
SHELL := /bin/zsh
6+
PLATFORM := macos
7+
endif
8+
9+
BUILD_DIR := build
10+
OBJ_DIR := $(BUILD_DIR)/obj
11+
BIN_DIR := $(BUILD_DIR)/bin
12+
13+
# ---------- NTSC library sources (platform-independent) --------------------
14+
NTSC_CPP := \
15+
src/common/ntsc_signal.cpp \
16+
src/common/ntsc_params.cpp \
17+
src/common/ntsc_effects.cpp \
18+
src/common/ntsc_encoder.cpp \
19+
src/common/ntsc_decoder.cpp \
20+
src/common/ntsc_processor.cpp
21+
22+
NTSC_OBJS := $(NTSC_CPP:src/%.cpp=$(OBJ_DIR)/%.o)
23+
24+
# ---------- Plugin sources (shared across platforms) -----------------------
25+
PLUGIN_SRC := src/plugin/rf2_ntsc.cpp
26+
PLUGIN_OBJ := $(OBJ_DIR)/plugin/rf2_ntsc.o
27+
PLUGIN_R := src/plugin/rf2_ntsc.r
28+
29+
# ==========================================================================
30+
ifeq ($(PLATFORM),windows)
31+
# ===== Windows (MinGW-w64) — plugin only ==================================
32+
33+
CXX := g++
34+
CXXFLAGS := -std=c++20 -O3 -march=x86-64-v2 -ffast-math -flto \
35+
-Wall -Wextra -Wpedantic -Iinclude
36+
LDFLAGS := -flto -static-libgcc -static-libstdc++
37+
38+
AE_SDK_DIR := 3rdparty/windows/AfterEffectsSDK_25.6_61_win/ae25.6_61.64bit.AfterEffectsSDK
39+
PR_SDK_DIR := 3rdparty/windows/Premiere Pro 26.0 C++ SDK
40+
PIPL_TOOL := $(AE_SDK_DIR)/Examples/Resources/PiPLtool.exe
41+
42+
SDK_INCLUDES := \
43+
-I"$(AE_SDK_DIR)/Examples/Headers" \
44+
-I"$(AE_SDK_DIR)/Examples/Headers/SP" \
45+
-I"$(AE_SDK_DIR)/Examples/Util" \
46+
-I"$(PR_SDK_DIR)/Examples/Headers"
47+
48+
# MinGW compatibility: _WINDOWS triggers platform detection in the Adobe SDK
49+
# headers (SPConfig.h sets WIN_ENV, which enables Windows type definitions).
50+
# __int64 is an MSVC keyword that g++ doesn't recognize in strict C++ mode.
51+
SDK_COMPAT := -D_WINDOWS -DMSWindows -D"__int64=long long" -Wno-unknown-pragmas
52+
53+
# PiPL resource pipeline intermediates
54+
PIPL_RR := $(OBJ_DIR)/plugin/rf2_ntsc.rr
55+
PIPL_RRC := $(OBJ_DIR)/plugin/rf2_ntsc.rrc
56+
PIPL_RC := $(OBJ_DIR)/plugin/rf2_ntsc_pipl.rc
57+
PIPL_RES := $(OBJ_DIR)/plugin/rf2_ntsc_pipl.o
58+
59+
PLUGIN_DLL := $(BUILD_DIR)/plugin/Analog_NTSC.prm
60+
PLUGIN_INSTALLER := $(BUILD_DIR)/Analog-NTSC-Setup.exe
61+
62+
.PHONY: plugin plugin-release clean
63+
64+
plugin: $(PLUGIN_DLL)
65+
66+
# Self-extracting installer (requires NSIS: pacman -S mingw-w64-x86_64-nsis)
67+
plugin-release: $(PLUGIN_INSTALLER)
68+
69+
$(PLUGIN_DLL): $(NTSC_OBJS) $(PLUGIN_OBJ) $(PIPL_RES)
70+
@mkdir -p "$(@D)"
71+
$(CXX) -shared -o "$@" $^ $(LDFLAGS)
72+
73+
$(PLUGIN_INSTALLER): $(PLUGIN_DLL)
74+
makensis src/plugin/installer.nsi
75+
76+
# PiPL resource pipeline: .r -> preprocess -> PiPLTool -> preprocess -> windres
77+
$(PIPL_RR): $(PLUGIN_R)
78+
@mkdir -p $(@D)
79+
$(CXX) -E -P -w -x c $(SDK_INCLUDES) $(SDK_COMPAT) \
80+
-I"$(AE_SDK_DIR)/Examples/Resources" \
81+
$< > $@
82+
83+
$(PIPL_RRC): $(PIPL_RR)
84+
"$(PIPL_TOOL)" $< $@
85+
86+
# PiPLtool emits MSVC rc.exe syntax; fix three issues for GNU windres:
87+
# 1. Remove DISCARDABLE (unsupported for custom resource types)
88+
# 2. Strip L suffix from integer literals (0x65564552L -> 0x65564552)
89+
# 3. Add missing commas between data values
90+
$(PIPL_RC): $(PIPL_RRC)
91+
$(CXX) -E -P -DMSWindows -w -x c $< | \
92+
sed -e 's/DISCARDABLE//' \
93+
-e 's/\([0-9a-fA-F]\)L\([, ]\)/\1\2/g' \
94+
-e 's/\([0-9a-fA-F]\)L$$/\1/' \
95+
-e '/^ /{ /,[[:space:]]*$$/!s/$$/,/; }' \
96+
> $@
97+
98+
$(PIPL_RES): $(PIPL_RC)
99+
windres $< -o $@
100+
101+
# Plugin source (with SDK includes)
102+
$(PLUGIN_OBJ): $(PLUGIN_SRC)
103+
@mkdir -p $(@D)
104+
$(CXX) $(CXXFLAGS) $(SDK_INCLUDES) $(SDK_COMPAT) \
105+
-fvisibility=hidden -Wno-multichar \
106+
-Wno-unused-parameter -Wno-missing-field-initializers \
107+
-c $< -o $@
108+
109+
# NTSC library objects (explicit subdirectory rule for Windows Make compatibility)
110+
$(OBJ_DIR)/common/%.o: src/common/%.cpp
111+
@mkdir -p $(dir $@)
112+
$(CXX) $(CXXFLAGS) -c $< -o $@
113+
114+
else
115+
# ===== macOS (clang++) =====================================================
116+
117+
CXX := clang++
118+
OBJCXX := clang++
119+
120+
CXXFLAGS := -std=c++20 -O3 -march=native -ffast-math -flto -Wall -Wextra -Wpedantic -Iinclude
121+
OBJCXXFLAGS := $(CXXFLAGS) -fobjc-arc
122+
LDFLAGS := -lcompression -flto
123+
124+
FRAMEWORKS_APP := \
125+
-framework Cocoa \
126+
-framework Metal \
127+
-framework MetalKit \
128+
-framework AVFoundation \
129+
-framework AudioToolbox \
130+
-framework CoreAudio \
131+
-framework QuartzCore
132+
133+
# macOS COMMON includes ntrf_container (uses Apple compression library)
134+
COMMON_CPP := src/common/ntrf_container.cpp $(NTSC_CPP)
135+
COMMON_OBJS := $(COMMON_CPP:src/%.cpp=$(OBJ_DIR)/%.o)
136+
137+
ENCODER_CPP := src/encoder/main.cpp
138+
ENCODER_OBJS := $(ENCODER_CPP:src/%.cpp=$(OBJ_DIR)/%.o)
139+
140+
APP_MM := src/app/main.mm
141+
APP_OBJS := $(APP_MM:src/%.mm=$(OBJ_DIR)/%.o)
142+
143+
ENCODER_BIN := $(BIN_DIR)/ntsc-encode
144+
PLAYER_BIN := $(BIN_DIR)/ntsc-player
145+
146+
NDI_SDK_DIR := ndisdk
147+
NDI_APP_CPPFLAGS :=
148+
NDI_APP_LDFLAGS :=
149+
ifneq ($(wildcard $(NDI_SDK_DIR)/include/Processing.NDI.Lib.h),)
150+
NDI_APP_CPPFLAGS += -DHAVE_NDI_SDK=1 -I$(NDI_SDK_DIR)/include
151+
NDI_APP_LDFLAGS += -L$(NDI_SDK_DIR)/lib/macOS -lndi -Wl,-rpath,@executable_path/../../ndisdk/lib/macOS
152+
endif
153+
154+
# ---------- Adobe plugin SDK paths (macOS) ---------------------------------
155+
AE_SDK_DIR := 3rdparty/macos/AfterEffectsSDK_25.6_61_mac/ae25.6_61.64bit.AfterEffectsSDK
156+
PR_SDK_DIR := 3rdparty/macos/Premiere Pro 26.0 C++ SDK
157+
158+
PLUGIN_STAMP := $(BUILD_DIR)/plugin/.stamp
159+
160+
# ---------- targets --------------------------------------------------------
161+
.PHONY: all clean run-player plugin plugin-release
162+
163+
all: $(ENCODER_BIN) $(PLAYER_BIN)
164+
165+
$(ENCODER_BIN): $(COMMON_OBJS) $(ENCODER_OBJS) | $(BIN_DIR)
166+
$(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
167+
168+
$(PLAYER_BIN): $(COMMON_OBJS) $(APP_OBJS) | $(BIN_DIR)
169+
$(OBJCXX) $(OBJCXXFLAGS) $(NDI_APP_CPPFLAGS) $^ -o $@ $(LDFLAGS) $(NDI_APP_LDFLAGS) $(FRAMEWORKS_APP)
170+
171+
$(OBJ_DIR)/%.o: src/%.cpp
172+
@mkdir -p $(dir $@)
173+
$(CXX) $(CXXFLAGS) -c $< -o $@
174+
175+
$(OBJ_DIR)/%.o: src/%.mm
176+
@mkdir -p $(dir $@)
177+
$(OBJCXX) $(OBJCXXFLAGS) $(NDI_APP_CPPFLAGS) -c $< -o $@
178+
179+
$(BIN_DIR):
180+
@mkdir -p $(BIN_DIR)
181+
182+
run-player: $(PLAYER_BIN)
183+
$(PLAYER_BIN)
184+
185+
# ---------- Premiere Pro plugin (macOS) ------------------------------------
186+
plugin: $(PLUGIN_STAMP)
187+
188+
$(PLUGIN_OBJ): $(PLUGIN_SRC)
189+
@mkdir -p $(@D)
190+
$(CXX) $(CXXFLAGS) \
191+
-I'$(AE_SDK_DIR)/Examples/Headers' \
192+
-I'$(AE_SDK_DIR)/Examples/Headers/SP' \
193+
-I'$(AE_SDK_DIR)/Examples/Util' \
194+
-I'$(PR_SDK_DIR)/Examples/Headers' \
195+
-fvisibility=hidden -Wno-four-char-constants \
196+
-Wno-unused-parameter -Wno-missing-field-initializers \
197+
-c $< -o $@
198+
199+
$(PLUGIN_STAMP): $(COMMON_OBJS) $(PLUGIN_OBJ) $(PLUGIN_R) src/plugin/Info.plist
200+
@mkdir -p '$(BUILD_DIR)/plugin/Analog NTSC.plugin/Contents/MacOS'
201+
@mkdir -p '$(BUILD_DIR)/plugin/Analog NTSC.plugin/Contents/Resources'
202+
$(CXX) -dynamiclib -o '$(BUILD_DIR)/plugin/Analog NTSC.plugin/Contents/MacOS/Analog NTSC' \
203+
$(COMMON_OBJS) $(PLUGIN_OBJ) $(LDFLAGS)
204+
xcrun Rez -d AE_OS_MAC \
205+
-I '$(AE_SDK_DIR)/Examples/Headers' \
206+
-I '$(AE_SDK_DIR)/Examples/Resources' \
207+
-I '$(PR_SDK_DIR)/Examples/Headers' \
208+
$(PLUGIN_R) -o '$(BUILD_DIR)/plugin/Analog NTSC.plugin/Contents/Resources/Analog NTSC.rsrc'
209+
cp src/plugin/Info.plist '$(BUILD_DIR)/plugin/Analog NTSC.plugin/Contents/Info.plist'
210+
@touch $@
211+
212+
# ---------- Plugin installer DMG -------------------------------------------
213+
PLUGIN_PKG := $(BUILD_DIR)/Install Analog NTSC.pkg
214+
PLUGIN_DMG := $(BUILD_DIR)/Analog-NTSC.dmg
215+
PLUGIN_INSTALL_DIR := /Library/Application Support/Adobe/Common/Plug-ins/7.0/MediaCore
216+
217+
plugin-release: $(PLUGIN_DMG)
218+
219+
$(PLUGIN_DMG): $(PLUGIN_STAMP)
220+
@rm -rf '$(BUILD_DIR)/pkg-root' '$(BUILD_DIR)/dmg-stage'
221+
@mkdir -p '$(BUILD_DIR)/pkg-root'
222+
@cp -R '$(BUILD_DIR)/plugin/Analog NTSC.plugin' '$(BUILD_DIR)/pkg-root/'
223+
pkgbuild --root '$(BUILD_DIR)/pkg-root' \
224+
--identifier day.kevin.analog-ntsc \
225+
--version 1.0 \
226+
--install-location '$(PLUGIN_INSTALL_DIR)' \
227+
'$(PLUGIN_PKG)'
228+
@mkdir -p '$(BUILD_DIR)/dmg-stage'
229+
@mv '$(PLUGIN_PKG)' '$(BUILD_DIR)/dmg-stage/'
230+
hdiutil create -volname 'Analog NTSC' \
231+
-srcfolder '$(BUILD_DIR)/dmg-stage' \
232+
-ov -format UDZO \
233+
'$(PLUGIN_DMG)'
234+
@rm -rf '$(BUILD_DIR)/pkg-root' '$(BUILD_DIR)/dmg-stage'
235+
@echo '=> $(PLUGIN_DMG)'
236+
237+
endif
238+
# ==========================================================================
239+
240+
clean:
241+
rm -rf $(BUILD_DIR)

0 commit comments

Comments
 (0)