Settings.json file#
This file controls how the camera behaves and how your buttons, switches and displays are mapped. It lives in ~/cinemate/src/settings.json. You can edit it with any text editor; the settings take effect the next time you start Cinemate.
The prebuilt image works out of the box. You do not need to edit settings.json to start shooting. This page is a reference for when you want to customise hardware controls and behaviour.
The image ships with a stock settings.json that already holds working defaults for every section below — button and switch mappings, preview, and audio (for example, a 2-frame audio timecode offset on both microphone paths). Edit it only to change a mapping or tune behaviour.
For easy editing of settings on the preinstalled image file, type editsettings anywhere in Raspberry Pi terminal.
The configuration is structured as JSON. Each top‑level key describes a feature area of the system. Below is a tour of every section and what the options do.
welcome message#
Text or image displayed briefly when Cinemate starts.
"show_welcome_message": true,
"welcome_image": null,
"welcome_message": "THIS IS A COOL MACHINE"
Set show_welcome_message to true to display the configured startup splash for at least 3 seconds. Set it to false to skip the startup message entirely. If the key is missing, Cinemate defaults to showing the startup message. Older installs that still use show_startup_message continue to work as a fallback.
If Plymouth is active during boot, Cinemate waits until the spinner hands off before it shows the welcome message so the screen transition stays clean.
Set welcome_image to the path of a bitmap file to show a logo instead of text.
Example path: /home/pi/welcome_image.bmp.
If welcome_image is set, it overrides the text message.
system#
"system": {
"wifi_hotspot": {
"name": "CinePi",
"password": "11111111",
"enabled": false
}
}
name – the Wi‑Fi network name (SSID) broadcast by the Pi when hotspot mode is enabled.
password – password for joining the hotspot.
enabled – set to true to start the hotspot automatically on boot. If set to false, Cinemate can still serve its web UI on whatever network the Pi is connected to, as long as wlan0 or eth0 already has an IP address when Cinemate starts.
Use the hotspot when you need a direct connection in the field. Disable it during development so the Pi can join your regular Wi‑Fi and reach the internet. If you are connected to the Pi via Ethernet you can keep the hotspot on.
camera#
All per-port settings live inside a cam0 or cam1 block so every option for a given camera port is visible in one place. raw_buffer_count is the only global key.
"camera": {
"raw_buffer_count": 0,
"cam0": {
"geometry": {
"rotate_180": false,
"horizontal_flip": false,
"vertical_flip": false
},
"output": {
"hdmi_port": 0
},
"override_camera_name": false,
"camera_name": "Blackmagic Pocket Cinema Camera 4K",
"phase_lock": true
},
"cam1": {
"geometry": {
"rotate_180": false,
"horizontal_flip": false,
"vertical_flip": false
},
"output": {
"hdmi_port": 1
},
"override_camera_name": false,
"camera_name": "Blackmagic Pocket Cinema Camera 4K",
"phase_lock": true
}
}
raw_buffer_count – how many frames cinepi-raw keeps in RAM as a write-burst absorber. Leave it at 0 (default); the active storage profile picks the right depth automatically.
raw_buffer_count / CMA buffer tuning
The sensor produces frames at a fixed rate but storage write speed is uneven — exFAT can stall during cluster allocation or directory updates. Frames that land during a stall are held in the RAM ring until the disk catches up; no frames are dropped as long as the stall is shorter than the buffer depth. More buffers = more RAM used, but more tolerance for storage hiccups. 0 (default) lets the active storage profile pick the right depth for your sensor, filesystem, and storage type — this is almost always correct. Raise it only if you see single-frame TC holes (DROP flashing) and grep Cma /proc/meminfo confirms spare CMA headroom (~25 MB per extra buffer at 4K).
geometry#
Controls image orientation for the camera mounted on this port. These settings let you mount cameras in any orientation and still get an upright preview and recording.
rotate_180 – flip the image upside-down.
horizontal_flip – mirror the image left/right.
vertical_flip – mirror the image top/bottom.
output#
Maps the camera to an HDMI connector.
hdmi_port – 0 for HDMI-A-1, 1 for HDMI-A-2.
This setting chooses which connector cinepi-raw uses at runtime. On Raspberry Pi Bookworm with KMS, the boot framebuffer mode still comes from /boot/firmware/cmdline.txt, so headless installs should also set a video=HDMI-A-1:1920x1080M@60D or video=HDMI-A-2:1920x1080M@60D override there.
camera name#
override_camera_name – when true, the value of camera_name is passed to cinepi-raw as --unique-camera-model and written into the UniqueCameraModel DNG tag of every recorded frame. When false, cinepi-raw uses its built-in default.
camera_name – the string to embed when override_camera_name is true.
Why Blackmagic Pocket Cinema Camera 4K
DaVinci Resolve uses the UniqueCameraModel DNG tag to identify the camera and select the matching decode pipeline. When this tag matches a known Blackmagic camera, Resolve unlocks the full Camera RAW tab — including the ISO slider, colour science selection (Gen 4 / Gen 5), and the corresponding tone curve and noise reduction presets. With an unknown or missing camera model the RAW tab is limited and ISO behaves as a simple exposure offset rather than selecting a proper decode curve.
Setting camera_name to "Blackmagic Pocket Cinema Camera 4K" is therefore not cosmetic — it is what makes Resolve treat the footage as genuine BRAW-adjacent DNG and apply the correct ISO-aware decode.
phase_lock#
phase_lock – true (default) keeps audio and video aligned over long takes by locking the recorded frame cadence to the Pi clock. Leave it on.
phase_lock internals and multi-camera genlock
The phase lock is a per-frame servo: it measures the accumulated frame phase against the nominal FPS (against the Pi wall clock — FrameWallClock, the same clock the audio is captured against) and continuously trims FrameDurationLimits, dithering the integer line-blanking so the average recorded cadence is exact. The result is that the video tracks the Pi clock, so audio and video do not drift apart over long takes (the residual is a bounded sub-frame offset, not an accumulating drift). It pre-converges during preview, so a clip is locked from the first frame.
Cinemate writes this per-camera flag to the shared fps_phase_lock runtime key, which cinepi-raw reads (it is off by default in cinepi-raw itself when run standalone). The loop is VBLANK-only and holds the recorded cadence on the nominal FPS directly, so no per-sensor FPS-correction table is needed.
Multi-camera genlock. phase_lock can stay true on a multi-camera --sync (beam-splitter / genlock) rig. cinepi-raw infers its role from --sync: the master (--sync server) runs the phase lock and disciplines the pair to the Pi clock, while the --sync client automatically suppresses its own phase lock and lets libcamera's rpi.sync hold the relative camera-to-camera (A→B) alignment. One setting works for single and dual — no per-camera differentiation. See Dual sensors.
hdmi_gui#
Controls optional HDMI GUI overlays.
"hdmi_gui": {
"buffer_vu_meter": false,
"vu_meter_hatch_lines": true
}
buffer_vu_meter – show or hide the vertical RAM-buffer meter on the HDMI GUI.
vu_meter_hatch_lines – draw hatch lines inside the buffer meter fill.
hdmi_display#
Sets the preferred HDMI GUI canvas size.
"hdmi_display": {
"width": 1920,
"height": 1080
}
Use this to tell Cinemate what size GUI canvas you want to target. If the active framebuffer is smaller, Cinemate now falls back to the active framebuffer size instead of drawing a clipped 1920x1080 layout into a smaller mode.
preview#
Adjusts zoom levels for the HDMI/browser preview.
"preview": {
"default_zoom": 1.0,
"zoom_steps": [1.0, 1.5, 2.0],
"default_hdmi_source": "both",
"pip": {
"scale": 0.28,
"corner": "lower_right",
"margin": 0.03
}
}
default_zoom – magnification factor used at startup.zoom_steps – list of zoom factors you can cycle through with the set_zoom_step command.default_hdmi_source – dual-sensor HDMI preview source at startup: both, cam0, cam1, pip_cam0, or pip_cam1. Switch it live with set preview. No effect with a single sensor.
pip – picture-in-picture inset geometry for the pip_cam0 / pip_cam1 preview modes.scale – inset size as a fraction of the main pane (default 0.28).corner – lower_right, lower_left, upper_right, or upper_left (default lower_right).margin – gap from the edge as a fraction of the pane (default 0.03). See Dual sensors.
lock_dual_recording#
"lock_dual_recording": false
Dual-sensor record policy. false (default) makes recording follow the HDMI preview: a full-screen or pip-main sensor records alone, side-by-side records both. true forces both sensors to record every take regardless of the preview. A camera token on rec (rec cam0 / rec cam1 / rec both) overrides either mode for one take. No effect with a single sensor. See Dual sensors › Recording.
audio#
Audio capture options shared by idle monitoring and recorded WAV input level. The stock file applies a 2-frame timecode offset on both paths.
"audio": {
"24bit": {
"capture_gain_db": 6.0,
"timecode_offset_frames": 2
},
"16bit": {
"capture_gain_db": 6.0,
"timecode_offset_frames": 2
}
}
Settings are split by the bit depth negotiated with the connected microphone. 24bit applies when the mic supports 24-bit stereo capture (mic_24bit ALSA alias); 16bit applies when only 16-bit mono is available (mic_16bit alias).
capture_gain_db – target ALSA capture gain in decibels applied when the microphone is detected. 0.0 means unity gain. Positive values boost the capture level, negative values attenuate it. For 16-bit mics this value is also passed into cinepi-raw via Redis so that a post-take software gain can be applied to the WAV if the hardware exposes no writable ALSA control.
timecode_offset_frames – frame offset applied to the WAV timecode metadata after each take. A positive value moves the WAV timecode later (use when audio arrives early relative to video); a negative value moves it earlier. Only the embedded timecode is shifted — the PCM is never moved. 24bit.timecode_offset_frames is used whenever the capture helper is active (both 24-bit and 16-bit mics going through the helper). 16bit.timecode_offset_frames applies to 16-bit mics specifically, overriding the 24-bit value for that path.
Some USB microphones expose a writable ALSA capture control and some do not. When the mic supports it, Cinemate applies capture_gain_db via amixer when the microphone is detected. If the device exposes no compatible control, the setting is silently skipped and the log will note that the mic likely has fixed hardware gain.
anamorphic_preview#
For stretching the preview when using anamorphic lenses.
"anamorphic_preview": {
"default_anamorphic_factor": 1,
"anamorphic_steps": [1, 1.33, 2.0]
}
default_anamorphic_factor – factor loaded when Cinemate starts.
anamorphic_steps – selectable squeeze factors; values above 1.0 widen the image.
gpio_output#
Defines pins used for visual feedback or sync signals.
"gpio_output": {
"pwm_pin": 19,
"rec_out_pin": [6, 21],
"rec_tone_pin": [18],
"rec_tone_frequency_hz": 1000,
"rec_tone_duty_cycle": 50
}
-
pwm_pin– outputs a strobe for shutter sync or external devices. -
rec_out_pin– list of pins pulled high while recording (useful for tally LEDs). -
rec_tone_pin– optional tone output pin(s) used as recording sync tone. You can pass a single pin or a list of pins. GPIO18and19use hardware PWM (preferred for stable tone generation). Any other pin uses software PWM fallback. The tone starts as soon as recording is requested (is_recording = 1), even before REC-light write confirmation, stops once writing stops (is_writing = 0), and is muted during storage pre-roll. Ifrec_tone_pinis unset or an empty list, Cinemate falls back topwm_pinfor backward compatibility. -
rec_tone_frequency_hz– tone frequency in hertz. -
rec_tone_duty_cycle– PWM duty cycle percentage (0–100). rec_tone_relay_drop_frames– whentrue, each live drop-frame pulse (drop_frame_relay = 1) briefly mutes REC tone output for about one frame, then resumes automatically.
settings#
General options for runtime behaviour.
"settings": {
"auto_storage_preroll": true,
"light_hz": [50, 60],
"conform_frame_rate": 25,
"live_sync_warning_tolerance_frames": 2,
"final_sync_analysis_tolerance_frames": 1
}
auto_storage_preroll – controls the short automatic warm-up recording that prepares mounted media before the first real take. Set it to true to run the warm-up on startup and when RAW storage mounts. Set it to false to skip only the automatic startup and mount-triggered pre-rolls. Manual storage preroll CLI runs remain available either way.
light_hz – list of mains frequencies used to calculate flicker‑free shutter angles. These are added to the shutter angle array and also dynamically calculated upon each fps change. This way, there is always a flicker free shutter angle value close by, when toggling through shutter angles, either via the cli or using buttons/pots/rotary encoder.
conform_frame_rate – frame rate intendend for project conforming in post. This setting is not really used by CineMate except for calculating the recording timecode tracker in redis but might be used in future updates.
live_sync_warning_tolerance_frames – frame-slot tolerance for the live magenta SYNC warning during a take. The default is 2, so brief +/- 2 frame live drift is allowed before the warning latches.
final_sync_analysis_tolerance_frames – frame tolerance for the end-of-take DNG count analysis after buffered frames have flushed. The default is 1, keeping the final result stricter than the live warning.
arrays#
Preset lists for exposure and frame‑rate settings. Cinemate will step through these values unless you enable free mode, either in the settings file or during runtime.
"arrays": {
"iso_steps": [100, 200, 400, 640, 800, 1200, 1600, 2500, 3200],
"shutter_a_steps": [1, 45, 90, 135, 172.8, 180, 225, 270, 315, 346.6, 360],
"fps_steps": [1, 2, 4, 8, 12, 16, 18, 24, 25, 33, 40, 50],
"wb_steps": [3200, 4400, 5600]
}
How to think about ISO
At capture, ISO is real analog gain on the sensor — it changes the raw pixel values written to disk. Setting it too high introduces noise that is baked in and cannot be removed later.
Once your DNGs are in Resolve's Camera RAW tab, the pixel values are fixed. ISO there is a decode-time parameter: in Gen 4 color science it selects a different log curve that shifts contrast as well as brightness; in Gen 5 it acts as a linear gain equivalent to the Exposure slider. Either way, correcting a wrong ISO in Resolve costs no additional quality — provided the sensor data was not catastrophically over- or underexposed at capture.
References: BRAW decode · Gen 4 vs Gen 5 · ISO vs Exposure · Resolve Camera RAW manual
analog_controls#
Maps Grove Base HAT ADC channels to analogue dials (potentiometers). Use null to disable a dial.
"analog_controls": {
"iso_pot": 0,
"shutter_a_pot": 2,
"fps_pot": 4,
"wb_pot": "None"
}
When using a Grove Base Hat with potentiometers, make sure to define only channels actually connected to potentiometers, since noise from unused connectors might trigger false readings.
free_mode#
When enabled, ignores the preset arrays and exposes the expanded runtime step tables used by potentiometers, rotary encoders, CLI commands, and the web GUI. White balance free mode uses 100 K steps from 2800 K through 6500 K.
"free_mode": {
"iso_free": false,
"shutter_a_free": false,
"fps_free": true,
"wb_free": false
}
resolutions#
Choose which sensor modes are practical to expose in the UI when cycling resolutions. This is a filter, not the mode list itself: every mode a sensor supports lives in the sensor database (resources/sensors.json, see sensors below), and resolutions selects the useful subset to show. Hidden modes stay technically available to the system.
"resolutions": {
"k_steps": [1.5, 2, 3, 4],
"bit_depths": [10, 12],
"custom_modes": {}
}
k_steps – K‑style categories for allowed widths. Modes are grouped to the nearest half‑K. Example: 1332×990 counts as 1.5 K.
bit_depths – list of bit depths to expose.
custom_modes – optional extra modes per sensor if the driver advertises none.
Design: full capability vs practical exposure
resources/sensors.json lists every mode each sensor supports, so all of them are technically available to the system. resolutions then exposes only the practical subset in the UI. Example: the IMX283 default k_steps: [3, 4] shows its ≥25 fps modes (2.7K and 4K) and hides the 5K modes (~18–21 fps); those 5K modes stay in sensors.json and reappear if you add 5.5. k_steps/bit_depths are global across all sensors.
sensors#
Points Cinemate at the sensor metadata database. It lists the full set of modes each sensor supports — every mode stays available to the system — alongside known packing modes, documentation metadata, and sustainable FPS annotations. The resolutions filter selects which of those modes appear in the UI.
"sensors": {
"database_file": "resources/sensors.json"
}
database_file – JSON file containing compatible sensor metadata. The default file is resources/sensors.json.
dynamic_resolution#
Automatically chooses the highest measured sustainable resolution for the user-selected frame rate, detected sensor, storage type, and storage filesystem.
"dynamic_resolution": {
"enabled": false,
"profile": "default",
"profiles_file": "resources/dynamic_resolution_profiles.json",
"policy": "highest_sustainable_resolution",
"safety_margin_fps": 0,
"match_tolerance_px": 32
}
enabled – set to true to allow Cinemate to switch resolution automatically when the current desired resolution cannot sustain the selected FPS.
profile – named standard measurement profile to load from profiles_file. The stock profile is default.
profiles_file – JSON file containing measured sustainable-FPS rows. The stock file is resources/dynamic_resolution_profiles.json.
policy – selection strategy. The current policy, highest_sustainable_resolution, chooses the largest measured mode that can sustain the requested FPS.
safety_margin_fps – subtract this many FPS from every measured row before deciding whether it is safe.
match_tolerance_px – pixel tolerance used when matching measured rows to driver modes. This lets a measured 3856 x 2180 row match a nearby driver mode such as 3840 x 2160.
How dynamic resolution decides, and the profile-row schema
Cinemate remembers the user's desired resolution. If you select a 4K mode and then raise FPS above that mode's measured sustainable limit, Cinemate switches to the highest measured mode that can sustain the FPS. When FPS returns to the desired mode's measured limit or below, Cinemate switches back. If no matching profile row exists for the detected sensor, storage type, filesystem, desired mode, and requested FPS, Cinemate leaves the current resolution unchanged.
When dynamic resolution is enabled, the maximum FPS shown by Cinemate comes from the measured dynamic-resolution profile for the current sensor, storage type, and filesystem, but only when the desired mode itself has a measured row. When dynamic resolution is disabled, maximum FPS comes from the sensor readout reported by cinepi-raw, as before.
The storage type comes from the mounted RAW device and is usually ssd, cfe, nvme, or unknown. The filesystem comes from the mounted RAW volume and is usually ext4, exfat, or ntfs.
Each profile row has this shape:
{
"sensor": "imx585",
"sensor_aliases": ["imx585_mono"],
"storage_type": "cfe",
"filesystem": "ext4",
"media_model": "CFE Hat / NVMe",
"width": 3856,
"height": 2180,
"bit_depth": 12,
"sustainable_fps": 40,
"max_fps_no_buffer": 40,
"test_duration_seconds": null,
"buffer_peak_frames": 0,
"drop_frames": 0,
"confidence": "empirical",
"notes": "4K desired-mode threshold for dynamic resolution."
}
sustainable_fps is the preferred field for new rows and means recording without dropped frames. max_fps_no_buffer is still accepted for older rows and for rows where you have verified no buffer growth as well.
Dynamic-resolution limits are determined by the selected stock JSON profile only. To change the lookup table, update resources/dynamic_resolution_profiles.json.
buttons#
Defines GPIO push buttons. Each entry describes one button and the actions it triggers.
{
"pin": 5,
"pull_up": true,
"debounce_time": 0.1,
"press_action": {"method": "rec"}
}
pin – BCM pin number the button is connected to.pull_up – set true if the pin idles high (internal pull‑up). Use false for pull‑down wiring.debounce_time – ignore additional presses within this time window (seconds).press_action, single_click_action, double_click_action, triple_click_action, hold_action – actions to perform for each type of interaction. Actions call Cinemate CLI commands with optional args.
Some push-buttons are wired closed = logic 1 and open = 0. At start-up, CineMate automatically detects buttons in state true and reverses them. This way the user can use any type of push buttons, both 1-0-1 and 0-1-0 types.
two_way_switches#
Latching on/off switches. Cinemate triggers an action whenever the state changes.
{
"pin": 27,
"state_on_action": {"method": "set_all_lock", "args": [1]},
"state_off_action": {"method": "set_all_lock", "args": [0]}
}
three_way_switches#
Three-position switches made from three GPIO inputs. Cinemate checks which pin is active and then runs the matching action.
{
"pins": [5, 6, 13],
"state_0_action": {"method": "set_fps", "args": [24]},
"state_1_action": {"method": "set_fps", "args": [25]},
"state_2_action": {"method": "set_fps", "args": [50]}
}
pins – the three GPIO inputs that represent the switch positions.
state_0_action, state_1_action, state_2_action – commands to run for each detected position.
If none of the three inputs is active, the switch is treated as being in an undefined position and no action is run.
combined_actions#
Combined actions let one button act as a modifier for another button.
"combined_actions": [
{
"hold_button_pin": 10,
"action_button_pin": 26,
"action_type": "press",
"action": {"method": "set_pwm_mode"}
}
]
hold_button_pin – button that must already be held.
action_button_pin – second button that triggers the combined action.
action_type – either press or release.
action – Cinemate command to run when the hold/action combination matches.
Combined actions only fire while the hold button is still held down. If the modifier button is not active, the normal per-button actions continue to run.
rotary_encoders#
Rotary encoders used for fine adjustment of settings. These can be wired straight to the GPIO pins of the Pi. The optional button_pin uses the same action grammar as the buttons section.
{
"enabled": true,
"clk_pin": 9,
"dt_pin": 11,
"button_pin": 10,
"pull_up": true,
"debounce_time": 0.05,
"button_actions": {
"press_action": {"method": "set_iso_lock"},
"hold_action": "None"
},
"encoder_actions": {
"rotate_clockwise": {"method": "inc_iso"},
"rotate_counterclockwise": {"method": "dec_iso"}
}
}
enabled – optional per-encoder switch; set false to keep an example in the file without claiming pins at startup.
clk_pin and dt_pin – the two pins of the encoder.
button_pin – optional BCM pin for the encoder push button.
button_actions – optional press/click/hold actions for the encoder push button.
encoder_actions – commands to run when turning the dial.
quad_rotary_controller#
Support for the Adafruit Neopixel Quad I2C rotary encoder breakout. Each entry maps one of the four dials to a setting and defines the push button actions similar to the buttons section. The stock settings include this mapping with enabled set to false; set it to true only when the board is connected.
"quad_rotary_controller": {
"enabled": true,
"encoders": {
"0": {"setting_name": "iso", "button": {"press_action": {"method": "rec"}}},
"1": {"setting_name": "shutter_a", "button": {"press_action": {"method": "set_fps_double"}}},
"2": {
"setting_name": "fps",
"button": {
"press_action": "None",
"single_click_action": {"method": "set_resolution"},
"double_click_action": {"method": "restart_cinemate"},
"triple_click_action": {"method": "reboot"},
"hold_action": {"method": "toggle_mount"}
}
},
"3": {"setting_name": "wb", "button": {"press_action": {"method": "rec"}}}
}
}
enabled – turn the quad rotary controller on or off.encoders – mapping of each dial to a setting and button actions.
i2c_oled#
Configuration for the optional OLED status screen. This can be useful for presenting extra information appart from the HDMI/web display.
"i2c_oled": {
"enabled": true,
"width": 128,
"height": 64,
"font_size": 30,
"values": ["write_speed_to_drive"]
}
enabled – turn the OLED display on or off.
width / height – pixel dimensions of your screen.
font_size – size of the displayed text.
values – list of Redis keys or pseudo‑keys to show (for example cpu_temp).
Available keys come from src/module/i2c/i2c_oled.py. Here are some examples:
iso, fps – basic camera settings.
shutter_a – shown as SHUTTER with a ° suffix.
wb_user – shown as WB with a trailing K.
space_left – displayed as SPACE in gigabytes.
write_speed_to_drive – write speed in MB/s.
resolution – prints width×height@bit_depth on the first line.
is_recording – draws a bullet ● when recording.
cpu_load, cpu_temp, memory_usage – Pi system statistics.
Other keys will display their name in uppercase and the raw value from Redis.