<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Notebook on</title><link>https://squad51.us/notebook/</link><description>Recent content in Notebook on</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 25 Aug 2025 16:40:35 -0700</lastBuildDate><atom:link href="https://squad51.us/notebook/index.xml" rel="self" type="application/rss+xml"/><item><title>Extract the Start Timecode from a Quicktime Movie</title><link>https://squad51.us/notebook/movie_timecode/</link><pubDate>Sun, 10 May 2026 18:55:19 -0700</pubDate><guid>https://squad51.us/notebook/movie_timecode/</guid><description>&lt;p&gt;This is a trifle but I was stuck on it for some time, even if you follow all
of the documentation there&amp;rsquo;s a trick to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; &lt;span style="color:#5dd8ff"&gt;AVFoundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; &lt;span style="color:#5dd8ff"&gt;CoreMedia&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;enum&lt;/span&gt; &lt;span style="color:#5dd8ff"&gt;MovieTimecodeExtractionError&lt;/span&gt;: Error {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; IntegrityError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;enum&lt;/span&gt; &lt;span style="color:#5dd8ff"&gt;MovieTimecodeExtractionResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; Success(CMTime)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; NoTimecodeTrack
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; NoTimecodeSamples
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// Get the first timecode value from a movie file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// This function uses AVFoundation and will attempt to load timecode tracks from the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// given movie. This is appropriate for QuickTime `.mov` and `.mp4`-type files.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// If the movie was succesfully read, the function will either return the time value as a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// `CMTime` if timecode was found, or `nil` if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// - The movie contained no timecode track, or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;/// - The movie contains a timecode track but that track has no timecode samples&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;///&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;func&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;extractStartTimecode&lt;/span&gt;(from url: URL) async &lt;span style="color:#fc5fa3"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; MovieTimecodeExtractionResult
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;asset&lt;/span&gt; = AVURLAsset(url: url)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// all of this is pretty straighforward...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;guard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;timecodeTrack&lt;/span&gt; = &lt;span style="color:#fc5fa3"&gt;try&lt;/span&gt; await asset.loadTracks(withMediaType: .timecode)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a167e6"&gt;first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;return&lt;/span&gt; .NoTimecodeTrack
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;reader&lt;/span&gt; = &lt;span style="color:#fc5fa3"&gt;try&lt;/span&gt; AVAssetReader(asset: asset)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;output&lt;/span&gt; = AVAssetReaderTrackOutput(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; track: timecodeTrack,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; outputSettings: &lt;span style="color:#fc5fa3"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reader.add(output)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;guard&lt;/span&gt; reader.startReading() &lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;throw&lt;/span&gt; reader.error!
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// This is where I got tripped-up...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// What I didn&amp;#39;t know was that the `output` here can (and does) return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// valid sampleBuffers that, despite being valid, contain no data...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;while&lt;/span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;sampleBuffer&lt;/span&gt; = output.copyNextSampleBuffer() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;guard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;formatDescription&lt;/span&gt;: CMFormatDescription =
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CMSampleBufferGetFormatDescription(sampleBuffer),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;blockBuffer&lt;/span&gt;: CMBlockBuffer = CMSampleBufferGetDataBuffer(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sampleBuffer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// ...so I&amp;#39;d get here, and when these two were nil, I initially assumed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// that this meant the output was exhausted. Not the case!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// If these are nil, that just means this sampleBuffer was empty, but&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// there are more sampleBuffers and the output will return these from&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// copyNextSampleBuffer, and you should only stop iterating the output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// when copyNextSampleBuffer returns nil.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// If we&amp;#39;re here, either of these were nil, and so the correct thing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// to do now is to advance to the next sampleBuffer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;frameQuanta&lt;/span&gt; = CMTimeCodeFormatDescriptionGetFrameQuanta(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; formatDescription
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;var&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;rawData&lt;/span&gt;: &lt;span style="color:#d0a8ff"&gt;UnsafeMutablePointer&lt;/span&gt;&amp;lt;&lt;span style="color:#d0a8ff"&gt;Int8&lt;/span&gt;&amp;gt;? = &lt;span style="color:#fc5fa3"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;var&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;length&lt;/span&gt;: &lt;span style="color:#d0a8ff"&gt;Int&lt;/span&gt; = &lt;span style="color:#d0bf69"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;var&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;totalLength&lt;/span&gt;: &lt;span style="color:#d0a8ff"&gt;Int&lt;/span&gt; = &lt;span style="color:#d0bf69"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;error&lt;/span&gt; = CMBlockBufferGetDataPointer(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; blockBuffer,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; atOffset: &lt;span style="color:#d0bf69"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lengthAtOffsetOut: &amp;amp;length,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; totalLengthOut: &amp;amp;totalLength,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dataPointerOut: &amp;amp;rawData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;guard&lt;/span&gt; error == kCMBlockBufferNoErr &lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;throw&lt;/span&gt; NSError(domain: NSOSStatusErrorDomain, code: &lt;span style="color:#d0a8ff"&gt;Int&lt;/span&gt;(error))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;guard&lt;/span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;tcData&lt;/span&gt; = rawData &lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// I&amp;#39;m not sure how we would get here if error was noErr.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;throw&lt;/span&gt; MovieTimecodeExtractionError.IntegrityError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;type&lt;/span&gt; = CMFormatDescriptionGetMediaSubType(formatDescription)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;frames&lt;/span&gt;: CMTimeValue?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;switch&lt;/span&gt; type {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; kCMTimeCodeFormatType_TimeCode32:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;fr0&lt;/span&gt; = tcData.withMemoryRebound(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to: &lt;span style="color:#d0a8ff"&gt;UInt32&lt;/span&gt;.&lt;span style="color:#fc5fa3"&gt;self&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; capacity: &lt;span style="color:#d0bf69"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { CFSwapInt32BigToHost(&lt;span style="color:#41a1c0"&gt;$0&lt;/span&gt;.pointee) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frames = CMTimeValue(fr0)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; kCMTimeCodeFormatType_TimeCode64:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;let&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;fr0&lt;/span&gt; = tcData.withMemoryRebound(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to: &lt;span style="color:#d0a8ff"&gt;UInt64&lt;/span&gt;.&lt;span style="color:#fc5fa3"&gt;self&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; capacity: &lt;span style="color:#d0bf69"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { CFSwapInt64BigToHost(&lt;span style="color:#41a1c0"&gt;$0&lt;/span&gt;.pointee) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frames = CMTimeValue(fr0)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// IF we&amp;#39;re here, `type` is probably one of the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// kCMTimeCodeFormatType_Counter* values, which are not useable to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// this function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frames = &lt;span style="color:#fc5fa3"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reader.cancelReading()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;return&lt;/span&gt; frames.flatMap {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .Success(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CMTime(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value: &lt;span style="color:#41a1c0"&gt;$0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timescale: CMTimeScale(frameQuanta)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } ?? .NoTimecodeSamples
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;// We&amp;#39;re here if the `while` never found a timecode databuffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;switch&lt;/span&gt; reader.status {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; .completed:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;return&lt;/span&gt; .NoTimecodeSamples
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;case&lt;/span&gt; .failed:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;throw&lt;/span&gt; reader.error!
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;throw&lt;/span&gt; MovieTimecodeExtractionError.IntegrityError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Doodles: Tuning Systems</title><link>https://squad51.us/notebook/tuning_systems/</link><pubDate>Wed, 08 Apr 2026 17:53:13 -0700</pubDate><guid>https://squad51.us/notebook/tuning_systems/</guid><description>&lt;!-- # Doodles: Tuning Systems --&gt;
&lt;p&gt;Some prelimiaries&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;%pip install tabulate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; math
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; itertools
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;from&lt;/span&gt; IPython.display &lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; display, HTML, display_html, display_markdown,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Markdown
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;from&lt;/span&gt; tabulate &lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; tabulate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d0a8ff"&gt;type&lt;/span&gt; Hz = &lt;span style="color:#d0a8ff"&gt;float&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d0a8ff"&gt;type&lt;/span&gt; Note = &lt;span style="color:#d0a8ff"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A_440_Note = &lt;span style="color:#d0bf69"&gt;69&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A_440_Hz = &lt;span style="color:#d0bf69"&gt;440.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;def&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;note_class&lt;/span&gt;(n: Note) -&amp;gt; &lt;span style="color:#d0a8ff"&gt;tuple&lt;/span&gt;[&lt;span style="color:#d0a8ff"&gt;int&lt;/span&gt;, &lt;span style="color:#d0a8ff"&gt;int&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; octaves, steps = &lt;span style="color:#d0a8ff"&gt;divmod&lt;/span&gt;(n, &lt;span style="color:#d0bf69"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;return&lt;/span&gt; octaves - &lt;span style="color:#d0bf69"&gt;1&lt;/span&gt;, steps
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;def&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;note_name&lt;/span&gt;(n: Note) -&amp;gt; &lt;span style="color:#d0a8ff"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7986"&gt;# MIDI note 24 is C1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; note_names = [&lt;span style="color:#fc6a5d"&gt;&amp;#39;C&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;C♯/D♭&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;D♯/E♭&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;E&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;F&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;F♯/G♭&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;G&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;G♯/A♭&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;A♯/B♭&amp;#39;&lt;/span&gt;, &lt;span style="color:#fc6a5d"&gt;&amp;#39;B&amp;#39;&lt;/span&gt;] octaves, steps = note_class(n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;return&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;f&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;{&lt;/span&gt;note_names[steps]&lt;span style="color:#fc6a5d"&gt;}{&lt;/span&gt;octaves&lt;span style="color:#fc6a5d"&gt;}&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;assert&lt;/span&gt; note_name(&lt;span style="color:#d0bf69"&gt;24&lt;/span&gt;) == &lt;span style="color:#fc6a5d"&gt;&amp;#39;C1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="12-tet-tempering"&gt;12-TET Tempering&lt;/h2&gt;
&lt;p&gt;12-tone Equal Temperament divides an octave into a twelve logarithmically-equal
parts. This is convenient because it has a very compact closed-form expression.&lt;/p&gt;</description></item><item><title>Slate with FFmpeg</title><link>https://squad51.us/notebook/slate_with_ffmpeg/</link><pubDate>Fri, 14 Nov 2025 10:53:13 -0800</pubDate><guid>https://squad51.us/notebook/slate_with_ffmpeg/</guid><description>&lt;p&gt;This is a little buggy with certain input movies but generally works great for
anything prores or h264 at standard 1080p resolution.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://squad51.us/images/Screenshot_slate_ffmpeg.png" alt="A screenshot of the slate this creates"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;#!/bin/bash&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# slated_output.bash &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Add slate to the beginning of a movie &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# by Jamie Hardt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# (c) 2025 Squad 51 Inc. All rights reserved.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# This will add:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# - a slate to the beginning of the input movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# - Three thumbnails taken from pre-selected times in the input movie will be &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# on the slate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# - A lower-third text will be printed to the entire length of the outpu &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# - Then entire output will be standardized to 1920x1080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# - Audio output is 48000 pcm_s24le&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# The INPUT_FILE is expected as argument 1 on the command line, the idea being&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# you might make a copy of this script for each project and customise the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# thumbnail positions, client and title, while the movie always changes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# The output file will be name INPUT_FILE_slated.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Enter project info here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;HEADLINE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;SOUND DESIGN REVIEW&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;TITLE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;\&amp;#34;TITLE\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;CLIENT&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;CLIENT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;CONTACT&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;CONTACT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;PIX_REF&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;PIC_REF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;MESSAGE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;MESSAGE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Enter the times for each thumbnail here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;THUMB1_TIME&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;00:00:37&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;THUMB2_TIME&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;00:08:39&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;THUMB3_TIME&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;00:11:00&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;MESSAGE_COLOR&lt;/span&gt;=yellow
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Enter the slate duration in seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;SLATE_DURATION&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Set a number here to play a test tone at -20 dBFS under the slate. Don&amp;#39;t set &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# it and the slate will be silent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# SLATE_TONE=440&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Font for slate titles. Leave it unset for the default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;FONT&lt;/span&gt;=/System/Library/Fonts/Avenir.ttc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Set this to &amp;#34;-to 20&amp;#34; while you&amp;#39;re testing your script out, once it looks &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# right then set it to &amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;OUTPUT_LENGTH_ARG&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;-to 20&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Set this to a positive number to move the middle block, the HEADLINE, TITLE &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# and CLIENT fields down/south, to avoid covering the thumbnails.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;MIDDLE_Y_NUDGE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;80&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Set this to a positive number to move the lower-third and &amp;#34;file&amp;#34; field in &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# the slate up/north, to avoid covering burnins&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;BOTTOM_Y_NUDGE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;#################################################################################&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;#####&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;##### DON&amp;#39;T EDIT BELOW THIS LINE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;if&lt;/span&gt; [ ! -z &lt;span style="color:#41a1c0"&gt;$FONT&lt;/span&gt; ]; &lt;span style="color:#fc5fa3"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;FONT&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;:fontfile=&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$FONT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;INPUT_FILE&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$1&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;INPUT_BASENAME&lt;/span&gt;=&lt;span style="color:#fc5fa3"&gt;$(&lt;/span&gt;basename -- &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc5fa3"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;OUTPUT_FILE&lt;/span&gt;=&lt;span style="color:#fc5fa3"&gt;$(&lt;/span&gt;dirname -- &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc5fa3"&gt;)&lt;/span&gt;/&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;${&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;INPUT_BASENAME&lt;/span&gt;%.*&lt;span style="color:#fc6a5d"&gt;}&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;_slated.mov&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7986"&gt;# Escape title, client and message fields in case they have quotes or colons&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;TITLE&lt;/span&gt;=&lt;span style="color:#fc5fa3"&gt;$(&lt;/span&gt;&lt;span style="color:#d0a8ff"&gt;echo&lt;/span&gt; -n &lt;span style="color:#41a1c0"&gt;$TITLE&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt; -s &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#39;:&amp;#34;&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc5fa3"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;CLIENT&lt;/span&gt;=&lt;span style="color:#fc5fa3"&gt;$(&lt;/span&gt;&lt;span style="color:#d0a8ff"&gt;echo&lt;/span&gt; -n &lt;span style="color:#41a1c0"&gt;$CLIENT&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt; -s &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#39;:&amp;#34;&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc5fa3"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;MESSAGE&lt;/span&gt;=&lt;span style="color:#fc5fa3"&gt;$(&lt;/span&gt;&lt;span style="color:#d0a8ff"&gt;echo&lt;/span&gt; -n &lt;span style="color:#41a1c0"&gt;$MESSAGE&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt; -s &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#39;:&amp;#34;&lt;/span&gt; | ffescape -p &lt;span style="color:#fc6a5d"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#fc5fa3"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#41a1c0"&gt;SLATE_AUDIO&lt;/span&gt;=&lt;span style="color:#fc6a5d"&gt;&amp;#34;-f lavfi -t &lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_DURATION&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt; -i &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;if&lt;/span&gt; [ -z &lt;span style="color:#41a1c0"&gt;$SLATE_TONE&lt;/span&gt; ]; &lt;span style="color:#fc5fa3"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;SLATE_AUDIO&lt;/span&gt;+=&lt;span style="color:#41a1c0"&gt;anullsrc&lt;/span&gt;=&lt;span style="color:#41a1c0"&gt;r&lt;/span&gt;=48000:cl=stereo,aformat=&lt;span style="color:#41a1c0"&gt;sample_fmts&lt;/span&gt;=s32:&lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;channel_layouts&lt;/span&gt;=stereo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;SLATE_AUDIO&lt;/span&gt;+=&lt;span style="color:#fc6a5d"&gt;&amp;#34;sine=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_TONE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;:r=48000,aformat=sample_fmts=s32:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;SLATE_AUDIO&lt;/span&gt;+=&lt;span style="color:#fc6a5d"&gt;&amp;#34;channel_layouts=stereo,aeval=val(ch):c=same&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffmpeg -y -hide_banner &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -f lavfi -i &lt;span style="color:#fc6a5d"&gt;&amp;#34;color=c=black:s=1920x1080:d=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_DURATION&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -ss &lt;span style="color:#41a1c0"&gt;$THUMB1_TIME&lt;/span&gt; -i &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -ss &lt;span style="color:#41a1c0"&gt;$THUMB2_TIME&lt;/span&gt; -i &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -ss &lt;span style="color:#41a1c0"&gt;$THUMB3_TIME&lt;/span&gt; -i &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -i &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$INPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#41a1c0"&gt;$SLATE_AUDIO&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -filter_complex &lt;span style="color:#fc6a5d"&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [1:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; tpad=stop_mode=clone:stop_duration=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_DURATION&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;[thumb1];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [2:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; tpad=stop_mode=clone:stop_duration=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_DURATION&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;[thumb2];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [3:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; tpad=stop_mode=clone:stop_duration=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$SLATE_DURATION&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;[thumb3];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [0:v][thumb1]overlay=100:100[tmp1];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [tmp1][thumb2]overlay=690:100[tmp2];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [tmp2][thumb3]overlay=1280:100[slate_raw];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [slate_raw]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; drawtext=text=&amp;#39;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$HEADLINE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:fontcolor=white:box=1:boxcolor=black@.6:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; boxborderw=10:fontsize=72:x=(w-text_w)/2:y=(h/2)-90+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$MIDDLE_Y_NUDGE$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; drawtext=text=&amp;#39;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$TITLE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:fontcolor=white:fontsize=48:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; x=(w-text_w)/2:y=(h/2)+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$MIDDLE_Y_NUDGE$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; drawtext=text=&amp;#39;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$CLIENT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:fontcolor=white:fontsize=48:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; x=(w-text_w)/2:y=(h/2)+60+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$MIDDLE_Y_NUDGE$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; drawtext=text=&amp;#39;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$CONTACT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:fontcolor=gray:fontsize=36:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; x=(w-text_w)/2:y=(h-(230+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$BOTTOM_Y_NUDGE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;))&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; drawtext=text=&amp;#39;Pix Ref\: &lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$PIX_REF&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:expansion=normal:fontcolor=gray:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; fontsize=36:x=(w-text_w)/2:y=(h-(180+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$BOTTOM_Y_NUDGE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;))&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;[slate];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [4:v]scale=1920:1080:force_original_aspect_ratio=decrease,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black, setsar=1:1[v1];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [4:a]aresample=48000,aformat=sample_fmts=s32:channel_layouts=stereo[a1];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [slate][5:a][v1][a1]concat=n=2:v=1:a=1[vcat][acat];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; [vcat]drawtext=text=&amp;#39;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$MESSAGE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;:fontcolor=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$MESSAGE_COLOR&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;:box=1:boxcolor=black:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; boxborderw=10:fontsize=42:x=(w-text_w)/2:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; y=h-(100+&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$BOTTOM_Y_NUDGE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;):fontfile=&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$FONT&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;[outv]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc6a5d"&gt; &amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -map &lt;span style="color:#fc6a5d"&gt;&amp;#34;[outv]&amp;#34;&lt;/span&gt; -map &lt;span style="color:#fc6a5d"&gt;&amp;#34;[acat]&amp;#34;&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -c:v libx264 -pix_fmt yuv420p -c:a pcm_s24le -movflags +faststart &lt;span style="color:#41a1c0"&gt;$OUTPUT_LENGTH_ARG&lt;/span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#41a1c0"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Pro Tools Markers from Resolve CSV Markers</title><link>https://squad51.us/notebook/markers_from_csv/</link><pubDate>Thu, 06 Nov 2025 19:49:39 -0800</pubDate><guid>https://squad51.us/notebook/markers_from_csv/</guid><description>&lt;p&gt;Just a little sketch of this; it&amp;rsquo;s very easy to whip something like this up
in a few minutes with &lt;a href="https://github.com/iluvcapra/py-ptsl"&gt;py-ptsl&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#fff;background-color:#1f1f24;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; csv
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; sys, re
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; ptsl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;from&lt;/span&gt; ptsl &lt;span style="color:#fc5fa3"&gt;import&lt;/span&gt; PTSL_pb2 &lt;span style="color:#fc5fa3"&gt;as&lt;/span&gt; pt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;def&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;create_marker&lt;/span&gt;(client: ptsl.Client, time: &lt;span style="color:#d0a8ff"&gt;str&lt;/span&gt;, notes: &lt;span style="color:#d0a8ff"&gt;str&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d0a8ff"&gt;print&lt;/span&gt;(&lt;span style="color:#fc6a5d"&gt;&amp;#34;Time: &lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;{}&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;\n\t&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;{}&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#34;&lt;/span&gt;.format(time, notes))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result = client.run_command(pt.CId_CreateMemoryLocation, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;: notes[&lt;span style="color:#d0bf69"&gt;0&lt;/span&gt;:&lt;span style="color:#d0bf69"&gt;32&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;start_time&amp;#39;&lt;/span&gt;: time,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;end_time&amp;#39;&lt;/span&gt;: time,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;time_properties&amp;#39;&lt;/span&gt;: &lt;span style="color:#fc6a5d"&gt;&amp;#39;TProperties_Marker&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;reference&amp;#39;&lt;/span&gt;: &lt;span style="color:#fc6a5d"&gt;&amp;#39;MLReference_Absolute&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;comments&amp;#39;&lt;/span&gt;: notes,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;color_index&amp;#39;&lt;/span&gt;: &lt;span style="color:#d0bf69"&gt;7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;location&amp;#39;&lt;/span&gt;: &lt;span style="color:#fc6a5d"&gt;&amp;#39;MarkerLocation_NamedRuler&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc6a5d"&gt;&amp;#39;track_name&amp;#39;&lt;/span&gt;: &lt;span style="color:#fc6a5d"&gt;&amp;#39;Robert Notes&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d0a8ff"&gt;print&lt;/span&gt;(result)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;def&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client = ptsl.Client(company_name=&lt;span style="color:#fc6a5d"&gt;&amp;#34;Squad 51&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; application_name=&lt;span style="color:#fc6a5d"&gt;&amp;#39;csv_import&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;for&lt;/span&gt; p in sys.argv[&lt;span style="color:#d0bf69"&gt;1&lt;/span&gt;:]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;with&lt;/span&gt; &lt;span style="color:#d0a8ff"&gt;open&lt;/span&gt;(p, &lt;span style="color:#fc6a5d"&gt;&amp;#34;r&amp;#34;&lt;/span&gt;) &lt;span style="color:#fc5fa3"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table = csv.DictReader(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;for&lt;/span&gt; row in table:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time = row[&lt;span style="color:#fc6a5d"&gt;&amp;#39;Record In&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; notes = row[&lt;span style="color:#fc6a5d"&gt;&amp;#39;Notes&amp;#39;&lt;/span&gt;].strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fc5fa3"&gt;if&lt;/span&gt; md := re.&lt;span style="color:#fc5fa3"&gt;match&lt;/span&gt;(&lt;span style="color:#fc6a5d"&gt;r&lt;/span&gt;&lt;span style="color:#fc6a5d"&gt;&amp;#39;^Marker \d+ - (.*)$&amp;#39;&lt;/span&gt;, notes):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; notes = md.group(&lt;span style="color:#d0bf69"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; create_marker(client, time, notes)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client.close()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fc5fa3"&gt;if&lt;/span&gt; &lt;span style="color:#41a1c0"&gt;__name__&lt;/span&gt; == &lt;span style="color:#fc6a5d"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>UCSINFER for Renaming Sounds</title><link>https://squad51.us/notebook/ucsinfer_to_rename_sounds/</link><pubDate>Sat, 30 Aug 2025 21:23:54 -0700</pubDate><guid>https://squad51.us/notebook/ucsinfer_to_rename_sounds/</guid><description>&lt;p&gt;After goofing around a bit with the &lt;a href="https://git.squad51.us/jamie/ucsinfer"&gt;ucsinfer&lt;/a&gt; &lt;code&gt;gather&lt;/code&gt; and
&lt;code&gt;evaluate&lt;/code&gt; I&amp;rsquo;ve built out the &lt;code&gt;recommend&lt;/code&gt; feature a bit.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note 9/6/2025:&lt;/strong&gt; This article was written around the time ucsinfer was at
commit &lt;a href="https://git.squad51.us/jamie/ucsinfer/src/commit/1a42d7d9f1c33fbe6668c67349a16c5a68495d5d"&gt;1a42d7d9&lt;/a&gt;. There have been signififcant changes to the codebase since
that time, including enhancements to the &lt;code&gt;recommend&lt;/code&gt; feature, but it should
still mostly work the way depicted here. Check the online documentation for
all the latest updates.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Category inference experiments with UCSINFER</title><link>https://squad51.us/notebook/category_inference_experiments_ucsinfer/</link><pubDate>Mon, 25 Aug 2025 14:24:06 -0700</pubDate><guid>https://squad51.us/notebook/category_inference_experiments_ucsinfer/</guid><description>&lt;p&gt;I&amp;rsquo;ve had some success auto-categorizing sounds into their corresponding
&lt;a href="https://universalcategorysystem.com"&gt;UCS categories&lt;/a&gt; by using an LLM and the technique of sentence embedding.
I&amp;rsquo;m writing up my process here and hope people find it useful and can maybe
take this forward to do other things.&lt;/p&gt;
&lt;p&gt;This is also my first post to the &amp;ldquo;Notebook&amp;rdquo; and am testing the posting system.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h3 id="how-i-learned-what-chatgpt-cant-do"&gt;How I Learned What ChatGPT Can&amp;rsquo;t Do&lt;/h3&gt;
&lt;p&gt;One of my original experiments with ChatGPT was to try to use it to
automatically select a UCS category for a given text description. This &lt;em&gt;seemed&lt;/em&gt;
like exactly the kind of problem ChatGPT should be able to solve well: it knows
that a Ford is a car, that explosions go bang and may invovlve gasoline or
black powder, inferring a category given the text description should be easy.&lt;/p&gt;</description></item></channel></rss>