Heartbeat: workspace updates

This commit is contained in:
OpenClaw Bot 2026-03-02 20:37:24 -06:00
parent e6dd6cca3c
commit e6687dfefc
5 changed files with 126 additions and 181 deletions

104
audiomix.md Normal file
View File

@ -0,0 +1,104 @@
# Podcast Audio Mixing Instructions - Layered/Professional Style
**For AI-Assisted Podcast Production**
*Version: 2.0 (Layered Overlap) | March 2026*
## Goal
Professional podcast sound: intro music starts first, voice fades in over it, music stays subtle underneath spoken word at 30% volume, then outro music fades after voice ends.
## Core Rules (MUST Follow)
- **Intro music**: Use the first 8 seconds only (`atrim=0:8`).
- **Outro music**: Use the last 8 seconds only (`atrim=26:34` for a 34s music source).
- **Music volume**: Fixed at `0.3` (30%).
- **No full-track loop**: Do not loop the entire source track.
- **No heavy dynamics**: Do not use `sidechaincompress` or ducking chains.
- **Layering is required**: Music must overlap spoken audio (intro overlap + low bed under narration + outro tail).
- Spoken narration remains primary and clear.
- Use smooth fades/crossfades (1.5-3 seconds).
- Output format: MP3 (VBR quality target around ~190 kbps, `-q:a 2`).
## Recommended FFmpeg Command (True Layered Mix)
This version does all of the following:
- Intro starts alone, voice enters at 5s with a 3s fade-in.
- Middle section is looped from the music's center slice (not full-track loop) for a continuous low bed.
- Voice and music are layered with a lightweight `amix` only.
- Outro is appended with a crossfade and fade-out.
```bash
#!/usr/bin/env bash
# mix_podcast_layered.sh
# Usage: ./mix_podcast_layered.sh spoken_narration.mp3 music_34s.mp3 final_podcast.mp3
set -euo pipefail
SPOKEN="${1:-}"
MUSIC="${2:-}"
OUTPUT="${3:-}"
if [ -z "$SPOKEN" ] || [ -z "$MUSIC" ] || [ -z "$OUTPUT" ]; then
echo "Usage: $0 spoken.mp3 music.mp3 output.mp3"
exit 1
fi
ffmpeg -y \
-i "$SPOKEN" \
-i "$MUSIC" \
-filter_complex "
[0:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,asetpts=PTS-STARTPTS[voice_raw];
[voice_raw]adelay=5000|5000,afade=t=in:st=5:d=3[voice];
[1:a]aformat=sample_fmts=fltp:sample_rates=48000:channel_layouts=stereo,asetpts=PTS-STARTPTS[music_base];
[music_base]atrim=0:8,volume=0.3,afade=t=in:st=0:d=1.5[intro];
[music_base]atrim=8:26,asetpts=PTS-STARTPTS,volume=0.3[mid];
[mid]aloop=loop=-1:size=2147483647,atrim=0:3600[mid_loop];
[intro][mid_loop]concat=n=2:v=0:a=1[music_timeline];
[music_timeline][voice]amix=inputs=2:duration=shortest:normalize=0[main];
[music_base]atrim=26:34,asetpts=PTS-STARTPTS,volume=0.3,afade=t=out:st=6:d=2[outro];
[main][outro]acrossfade=d=2:c1=tri:c2=tri[mix]
" \
-map "[mix]" \
-c:a libmp3lame -q:a 2 \
"$OUTPUT"
```
## Simpler Alternative (Intro/Outro Layering Only)
Use this if you want easier debugging. It overlaps intro into speech and appends outro, but does not maintain a continuous bed for very long narration.
```bash
ffmpeg -y \
-i "$SPOKEN" \
-i "$MUSIC" \
-filter_complex "
[1:a]atrim=0:8,volume=0.3,afade=t=in:st=0:d=2[intro];
[1:a]atrim=26:34,volume=0.3,afade=t=out:st=6:d=2[outro];
[intro][0:a]acrossfade=d=3:curve1=exp:curve2=exp[voiced];
[voiced][outro]acrossfade=d=2:curve1=tri:curve2=tri[mix]
" \
-map "[mix]" \
-c:a libmp3lame -q:a 2 \
"$OUTPUT"
```
## File Preparation Checklist
- Spoken narration: MP3/M4A/WAV, clean and normalized.
- Music source: 34s+ source where `0:8` is intro material and `26:34` is outro material.
- Validate durations first:
```bash
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$SPOKEN"
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$MUSIC"
```
- Test with a short spoken sample before full renders.
## Troubleshooting
- Music too loud: lower `volume=0.3` to `0.25` or `0.2`.
- Voice starts too late/early: adjust `adelay=5000|5000`.
- Intro overlap too long/short: adjust `afade` and crossfade durations.
- Outro too abrupt: increase `afade=t=out` duration or `acrossfade=d`.
- Want final loudness polish: add `-af loudnorm` to output stage.
## Notes
- This is your layered/pro baseline file for AI generation and scripting.
- If you want true broadcast polish next, the next step is LUFS target normalization + limiter (still without sidechain ducking).

View File

@ -1,93 +0,0 @@
# Audio Mixing - Podcast Production
## Overview
The blog-backup project generates podcast audio by mixing TTS (text-to-speech) with background music using ffmpeg.
## Current Working Configuration
### What It Does
- **TTS:** Uses macOS `say` command (built-in, no external API)
- **Mixing:** Music plays at 12% volume UNDER the speech (continuous bed)
- **Fades:** Music fades in at start (30%) and fades out at end (30%)
- **Format:** MP3 output
### Audio Flow
```
[Music fades in 30%] → [Speech with 12% music bed] → [Music fades out]
```
### Technical Details
**File:** `blog-backup/src/lib/tts.ts`
**Environment Variables:**
```bash
ENABLE_TTS=true
TTS_PROVIDER=macsay
ENABLE_PODCAST_MUSIC=true
INTRO_MUSIC_URL=/path/to/intro.mp3
OUTRO_MUSIC_URL=/path/to/outro.mp3
```
**ffmpeg Command (Working):**
```bash
ffmpeg -y -i "${ttsPath}" -stream_loop -1 -i "${introPath}" -i "${outroPath}" -filter_complex "
[1:a]volume=0.3,apad=5[music];
[2:a]volume=0.3[outro];
[0:a][music]amix=duration=first:weights=1 0.12[speechbed];
[speechbed]afade=t=in:st=0:d=1[in];
[in][outro]concat=n=2:v=0:a=1[out]
" -map "[out]" -shortest "${outputPath}"
```
### Known Limitations
1. **Complex filters fail:** More elaborate ffmpeg filter chains (trimming, looping specific segments) tend to fail with "Filter has output unconnected" errors
2. **Single bed approach works:** Using the same intro as a continuous bed is reliable
3. **Pre-sliced clips would be better:** For distinct intro/speech/outro, pre-create short clips (5-10 sec) and concatenate
## Music Files
**Location:** `blog-creator/public/podcast-audio/`
| File | Duration | Use |
|------|----------|-----|
| intro.mp3 | 71 sec | Background music bed |
| outro.mp3 | 34 sec | Outro music |
### Suggested Improvements
1. **Create short intro clip:** Extract first 5-10 sec as separate file
2. **Create short outro clip:** Extract last 5-10 sec as separate file
3. **Use simpler 2-step process:**
- Step 1: Mix speech with looped bed
- Step 2: Prepend intro, append outro
## Testing
```bash
# Test TTS with music
curl -X POST "http://localhost:3002/api/tts" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"text": "Your text here",
"includeMusic": true
}'
```
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| "Filter has output unconnected" | Complex filter chain | Simplify to fewer inputs |
| "OPENAI_API_KEY not configured" | Wrong provider | Set TTS_PROVIDER=macsay |
| "No music files configured" | Missing env vars | Set INTRO_MUSIC_URL and OUTRO_MUSIC_URL |
## Future Enhancements
- [ ] Pre-slice intro/outro for distinct segments
- [ ] Add transition sounds between stories
- [ ] Adjust bed volume based on speech pauses
- [ ] Add compression/normalize for consistent levels

View File

@ -1,65 +0,0 @@
# Daily Digest Podcast - PRD & Roadmap
## Current State
### ✅ DONE - What's Built & Working
**TTS Generation:**
- Provider: macOS `say` (built-in, no external API)
- Converts blog content to speech
**Audio Mixing:**
- Music plays at 12% volume UNDER speech (continuous bed)
- Music fades in at start (30%), fades out at end
- Works reliably with ffmpeg
**Files:**
- Intro: `blog-creator/public/podcast-audio/intro.mp3` (71 sec)
- Outro: `blog-creator/public/podcast-audio/outro.mp3` (34 sec)
**Tested:** Audio generates successfully with music bed!
---
## Configuration
```bash
# blog-backup .env.local
ENABLE_TTS=true
TTS_PROVIDER=macsay
ENABLE_PODCAST_MUSIC=true
INTRO_MUSIC_URL=/path/to/intro.mp3
OUTRO_MUSIC_URL=/path/to/outro.mp3
```
---
## What's Left to Do
### 1. Integrate TTS into Daily Digest Cron
- [ ] 7am cron creates digest but doesn't auto-generate audio
- [ ] Need to add TTS call to workflow
### 2. Pre-slice Intro/Outro (Optional Enhancement)
- [ ] Create 5-10 sec intro clip (currently using full 71 sec as bed)
- [ ] Create 5-10 sec outro clip
- [ ] This would enable distinct intro/speech/outro segments
### 3. Transition Sounds (Optional)
- [ ] Add brief music bump between stories
- [ ] Requires pre-sliced clips
---
## Documentation
**Full audio mixing docs:** `~/.openclaw/workspace/docs/AUDIO_MIXING.md`
---
## Test Result
**Working audio generated:**
- URL: `https://qnatchrjlpehiijwtreh.supabase.co/storage/v1/object/public/podcast-audio/tts-xxx.mp3`
- Duration: ~120 seconds (matches speech length)
- Sound: Speech with background music bed throughout

View File

@ -1,24 +1,23 @@
# Monday, March 2nd, 2026 - 12:46 PM CST
## 7:15 PM Heartbeat
## Heartbeat Check
**Time:** 12:46 PM CST
**Elapsed since last check:** ~1.5 hours
**Mission Control:** No active sprint found. API endpoint `/api/sprints` returning 404. Local API (`localhost:3000`) returning empty sprints list.
### Checks Performed:
**Git Status:** No changes in `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board`
**Mission Control:** ✅ Live (site working, API endpoints /status and /health return 404 as expected)
- URL: https://mission-control.twisteddevices.com
- Status: Running but no health endpoint yet
**Email/Calendar/Weather:** Skipped (no changes since last check at 7:15 PM)
**Calendar:** ✅ Clear
- No events scheduled in next 48 hours
**Status:** All checks completed in <30s. No alerts.
**Blog Backup:** ⏭️ Skipped (last check ~2 hours ago, within 4h window)
---
**Git Repository:** ✅ Cleaned up
- Found 2 changed files (docs/PODCAST_PRD.md, skills/daily-digest/SKILL.md)
- Committed and pushed to Gitea: TopDogLabs/test-repo
- New commit: 93555df - "Heartbeat: Update docs and remove old skill"
## 8:21 PM Heartbeat
### Summary:
All systems operational. Git maintenance completed. No urgent items.
**Email:** Checked - 2 unread (Gantt Board reminder, Vercel deployment notification - all good)
**Calendar:** Checked - No events in next 24h. All clear.
**Mission Control:** Checked - 3 new documents added since last check. All processed and tagged.
**Git Status:** Checked - All repos clean (gantt-board, blog-backup, mission-control)
**Status:** All checks completed in <30s. No urgent items. 🎉

View File

@ -1,9 +1,9 @@
{
"lastChecks": {
"mission-control": 1741198800,
"calendar": 1741198800,
"blog-backup": 1741191600,
"git": 1741198800
},
"lastRun": "2026-03-02T12:46:00-06:00"
"email": 1772504514,
"calendar": 1772504514,
"weather": null,
"missionControl": 1772504514,
"git": 1772504514
}
}