takeloom 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- takeloom-0.5.0/.github/workflows/daily.yml +90 -0
- takeloom-0.5.0/.github/workflows/release.yml +107 -0
- takeloom-0.5.0/.gitignore +20 -0
- takeloom-0.5.0/CLAUDE.md +24 -0
- takeloom-0.5.0/LICENSE +21 -0
- takeloom-0.5.0/PKG-INFO +21 -0
- takeloom-0.5.0/README.md +201 -0
- takeloom-0.5.0/camera_app/android/app/build.gradle.kts +32 -0
- takeloom-0.5.0/camera_app/android/app/src/main/AndroidManifest.xml +26 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/CameraEngine.kt +471 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/MainActivity.kt +402 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/ServerLink.kt +208 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/Settings.kt +48 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/Uploads.kt +190 -0
- takeloom-0.5.0/camera_app/android/app/src/main/java/com/priestc/takeloomcamera/Wire.kt +142 -0
- takeloom-0.5.0/camera_app/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.png +0 -0
- takeloom-0.5.0/camera_app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- takeloom-0.5.0/camera_app/android/app/src/main/res/values/ic_launcher_background.xml +5 -0
- takeloom-0.5.0/camera_app/android/app/src/main/res/values/strings.xml +4 -0
- takeloom-0.5.0/camera_app/android/build.gradle.kts +4 -0
- takeloom-0.5.0/camera_app/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- takeloom-0.5.0/camera_app/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- takeloom-0.5.0/camera_app/android/gradle.properties +4 -0
- takeloom-0.5.0/camera_app/android/gradlew +249 -0
- takeloom-0.5.0/camera_app/android/gradlew.bat +92 -0
- takeloom-0.5.0/camera_app/android/settings.gradle.kts +16 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/AppModel.swift +190 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Assets.xcassets/AppIcon.appiconset/icon-1024.png +0 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Assets.xcassets/Contents.json +3 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/CameraPipeline.swift +268 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/H264Encoder.swift +155 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Info.plist +53 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/ServerLink.swift +231 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/SessionRecorder.swift +113 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Settings.swift +74 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Uploads.swift +174 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Views.swift +212 -0
- takeloom-0.5.0/camera_app/ios/TakeloomCamera/Wire.swift +157 -0
- takeloom-0.5.0/camera_app/ios/project.yml +23 -0
- takeloom-0.5.0/docs/desktop-audio-capture.md +66 -0
- takeloom-0.5.0/docs/inspiration-server-autocomplete-api.md +196 -0
- takeloom-0.5.0/docs/prerequisites.md +78 -0
- takeloom-0.5.0/docs/releasing.md +68 -0
- takeloom-0.5.0/docs/takeloom-camera.md +104 -0
- takeloom-0.5.0/docs/youtube-streaming-setup.md +89 -0
- takeloom-0.5.0/pyproject.toml +43 -0
- takeloom-0.5.0/scripts/build_macos_dmg.py +17 -0
- takeloom-0.5.0/scripts/make_icon.py +276 -0
- takeloom-0.5.0/takeloom/__init__.py +1 -0
- takeloom-0.5.0/takeloom/__main__.py +1457 -0
- takeloom-0.5.0/takeloom/audio/__init__.py +0 -0
- takeloom-0.5.0/takeloom/audio/benchmark.py +93 -0
- takeloom-0.5.0/takeloom/audio/coreaudio_devices.py +134 -0
- takeloom-0.5.0/takeloom/audio/devices.py +18 -0
- takeloom-0.5.0/takeloom/audio/engine.py +393 -0
- takeloom-0.5.0/takeloom/audio/filters.py +130 -0
- takeloom-0.5.0/takeloom/audio/formats.py +81 -0
- takeloom-0.5.0/takeloom/audio/instrument_classifier.py +726 -0
- takeloom-0.5.0/takeloom/audio/metronome.py +45 -0
- takeloom-0.5.0/takeloom/audio/midi_input.py +323 -0
- takeloom-0.5.0/takeloom/audio/midi_log.py +203 -0
- takeloom-0.5.0/takeloom/audio/mixer.py +226 -0
- takeloom-0.5.0/takeloom/audio/pitch.py +220 -0
- takeloom-0.5.0/takeloom/audio/pitch_shift.py +282 -0
- takeloom-0.5.0/takeloom/audio/recorder.py +80 -0
- takeloom-0.5.0/takeloom/audio/scarlett2_direct_monitor.py +235 -0
- takeloom-0.5.0/takeloom/audio/soundfont.py +68 -0
- takeloom-0.5.0/takeloom/audio/synth.py +456 -0
- takeloom-0.5.0/takeloom/backend.py +6174 -0
- takeloom-0.5.0/takeloom/config.py +418 -0
- takeloom-0.5.0/takeloom/data/__init__.py +0 -0
- takeloom-0.5.0/takeloom/data/icon.png +0 -0
- takeloom-0.5.0/takeloom/data/measure_latency.wav +0 -0
- takeloom-0.5.0/takeloom/device_check.py +65 -0
- takeloom-0.5.0/takeloom/ffmpeg_bin.py +27 -0
- takeloom-0.5.0/takeloom/inspiration.py +331 -0
- takeloom-0.5.0/takeloom/instrument_colors.py +55 -0
- takeloom-0.5.0/takeloom/keyboard_drivers/__init__.py +106 -0
- takeloom-0.5.0/takeloom/keyboard_drivers/alesis_qx25.py +32 -0
- takeloom-0.5.0/takeloom/keyboard_drivers/m_audio_keystation_61es.py +19 -0
- takeloom-0.5.0/takeloom/launcher.py +198 -0
- takeloom-0.5.0/takeloom/net.py +24 -0
- takeloom-0.5.0/takeloom/phone_camera/__init__.py +2 -0
- takeloom-0.5.0/takeloom/phone_camera/hub.py +577 -0
- takeloom-0.5.0/takeloom/phone_camera/protocol.py +141 -0
- takeloom-0.5.0/takeloom/phone_camera/recorder.py +234 -0
- takeloom-0.5.0/takeloom/phone_camera/sync.py +343 -0
- takeloom-0.5.0/takeloom/processing/__init__.py +0 -0
- takeloom-0.5.0/takeloom/processing/splicer.py +547 -0
- takeloom-0.5.0/takeloom/project.py +308 -0
- takeloom-0.5.0/takeloom/recording_driver.py +621 -0
- takeloom-0.5.0/takeloom/remote/__init__.py +7 -0
- takeloom-0.5.0/takeloom/remote/backend.py +592 -0
- takeloom-0.5.0/takeloom/remote/client.py +190 -0
- takeloom-0.5.0/takeloom/remote/protocol.py +193 -0
- takeloom-0.5.0/takeloom/remote/server.py +414 -0
- takeloom-0.5.0/takeloom/rig_watcher.py +188 -0
- takeloom-0.5.0/takeloom/service.py +166 -0
- takeloom-0.5.0/takeloom/sleep_guard.py +129 -0
- takeloom-0.5.0/takeloom/streamdeck_controller.py +1119 -0
- takeloom-0.5.0/takeloom/streaming.py +169 -0
- takeloom-0.5.0/takeloom/take_video.py +110 -0
- takeloom-0.5.0/takeloom/ui/__init__.py +0 -0
- takeloom-0.5.0/takeloom/ui/add_to_setlist_chooser.py +65 -0
- takeloom-0.5.0/takeloom/ui/add_to_setlist_dialog.py +468 -0
- takeloom-0.5.0/takeloom/ui/app.py +339 -0
- takeloom-0.5.0/takeloom/ui/app_state.py +85 -0
- takeloom-0.5.0/takeloom/ui/audio_player.py +411 -0
- takeloom-0.5.0/takeloom/ui/backing_trim_editor.py +238 -0
- takeloom-0.5.0/takeloom/ui/completed_takes.py +467 -0
- takeloom-0.5.0/takeloom/ui/desktop_entry.py +77 -0
- takeloom-0.5.0/takeloom/ui/detect_test.py +380 -0
- takeloom-0.5.0/takeloom/ui/filter_fields.py +157 -0
- takeloom-0.5.0/takeloom/ui/instrument_colors.py +39 -0
- takeloom-0.5.0/takeloom/ui/latency.py +363 -0
- takeloom-0.5.0/takeloom/ui/level_meter.py +49 -0
- takeloom-0.5.0/takeloom/ui/new_project_dialog.py +78 -0
- takeloom-0.5.0/takeloom/ui/platform_style.py +69 -0
- takeloom-0.5.0/takeloom/ui/record.py +1764 -0
- takeloom-0.5.0/takeloom/ui/recording_devices.py +402 -0
- takeloom-0.5.0/takeloom/ui/remote.py +441 -0
- takeloom-0.5.0/takeloom/ui/sessions.py +387 -0
- takeloom-0.5.0/takeloom/ui/setlist_row.py +119 -0
- takeloom-0.5.0/takeloom/ui/song_mixer.py +428 -0
- takeloom-0.5.0/takeloom/ui/song_set_dialog.py +329 -0
- takeloom-0.5.0/takeloom/ui/streamdeck_emulator.py +150 -0
- takeloom-0.5.0/takeloom/ui/streaming.py +345 -0
- takeloom-0.5.0/takeloom/ui/studio_setup.py +1061 -0
- takeloom-0.5.0/takeloom/ui/tuner_meter.py +116 -0
- takeloom-0.5.0/takeloom/ui/video_check_dialog.py +61 -0
- takeloom-0.5.0/takeloom/update_check.py +187 -0
- takeloom-0.5.0/takeloom/utils.py +131 -0
- takeloom-0.5.0/takeloom/vault.py +322 -0
- takeloom-0.5.0/takeloom/vault_client.py +257 -0
- takeloom-0.5.0/takeloom/video/__init__.py +0 -0
- takeloom-0.5.0/takeloom/video/capture.py +390 -0
- takeloom-0.5.0/takeloom/video/devices.py +80 -0
- takeloom-0.5.0/takeloom/youtube.py +101 -0
- takeloom-0.5.0/takeloom/youtube_api.py +331 -0
- takeloom-0.5.0/vault_server/README.md +75 -0
- takeloom-0.5.0/vault_server/pyproject.toml +19 -0
- takeloom-0.5.0/vault_server/takeloom_vault/__init__.py +5 -0
- takeloom-0.5.0/vault_server/takeloom_vault/__main__.py +131 -0
- takeloom-0.5.0/vault_server/takeloom_vault/auth.py +202 -0
- takeloom-0.5.0/vault_server/takeloom_vault/server.py +369 -0
- takeloom-0.5.0/vault_server/takeloom_vault/store.py +173 -0
- takeloom-0.5.0/vault_server/takeloom_vault/takes.py +158 -0
- takeloom-0.5.0/vault_server/takeloom_vault/web.py +244 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Daily build: once a day, if anything was committed since the last build
|
|
2
|
+
# (daily or release), build takeloom and publish it as a GitHub pre-release
|
|
3
|
+
# tagged daily-YYYY-MM-DD. Never sent to PyPI/Homebrew/apt — that's
|
|
4
|
+
# release.yml. See docs/releasing.md.
|
|
5
|
+
name: Daily build
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
schedule:
|
|
9
|
+
# 07:00 UTC: midnight in Denver in winter (MST), 1am in summer (MDT) —
|
|
10
|
+
# always after the day being built has ended.
|
|
11
|
+
- cron: "0 7 * * *"
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
|
|
17
|
+
concurrency: daily-build
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
daily:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
env:
|
|
23
|
+
GH_TOKEN: ${{ github.token }}
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0 # tags + history: the version comes from them
|
|
28
|
+
|
|
29
|
+
- name: Anything new since the last build?
|
|
30
|
+
id: check
|
|
31
|
+
run: |
|
|
32
|
+
if [ -n "$(git tag --points-at HEAD --list 'daily-*' 'v[0-9]*')" ]; then
|
|
33
|
+
echo "Nothing committed since the last build — no daily build today."
|
|
34
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
# Named for the (Denver) day the newest commit was made.
|
|
38
|
+
day=$(TZ=America/Denver git log -1 --format=%cd --date=format-local:%Y-%m-%d)
|
|
39
|
+
previous=$(git describe --tags --abbrev=0 --match 'daily-*' --match 'v[0-9]*' 2>/dev/null || true)
|
|
40
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
41
|
+
echo "tag=daily-$day" >> "$GITHUB_OUTPUT"
|
|
42
|
+
echo "day=$day" >> "$GITHUB_OUTPUT"
|
|
43
|
+
echo "previous=$previous" >> "$GITHUB_OUTPUT"
|
|
44
|
+
|
|
45
|
+
- uses: actions/setup-python@v5
|
|
46
|
+
if: steps.check.outputs.skip == 'false'
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.12"
|
|
49
|
+
|
|
50
|
+
- name: Build
|
|
51
|
+
if: steps.check.outputs.skip == 'false'
|
|
52
|
+
run: |
|
|
53
|
+
python -m pip install --quiet build
|
|
54
|
+
python -m build
|
|
55
|
+
ls dist
|
|
56
|
+
|
|
57
|
+
- name: Smoke test
|
|
58
|
+
if: steps.check.outputs.skip == 'false'
|
|
59
|
+
run: |
|
|
60
|
+
sudo apt-get update -qq && sudo apt-get install -y -qq libportaudio2 libsndfile1
|
|
61
|
+
python -m pip install --quiet dist/*.whl
|
|
62
|
+
takeloom --help
|
|
63
|
+
|
|
64
|
+
- name: Publish pre-release
|
|
65
|
+
if: steps.check.outputs.skip == 'false'
|
|
66
|
+
run: |
|
|
67
|
+
tag="${{ steps.check.outputs.tag }}"
|
|
68
|
+
previous="${{ steps.check.outputs.previous }}"
|
|
69
|
+
version=$(ls dist/*.whl | sed -E 's/.*takeloom-([^-]+)-.*/\1/')
|
|
70
|
+
{
|
|
71
|
+
echo "Daily build of \`main\` for ${{ steps.check.outputs.day }} — version $version."
|
|
72
|
+
echo
|
|
73
|
+
echo "Not a release: for testing. Install the wheel with \`pipx install <url of the .whl>\`."
|
|
74
|
+
echo
|
|
75
|
+
echo "### Changes since ${previous:-the beginning}"
|
|
76
|
+
git log --format='- %s (%h)' ${previous:+$previous..}HEAD
|
|
77
|
+
} > notes.md
|
|
78
|
+
# A second build on the same day (manual run) replaces the first.
|
|
79
|
+
gh release delete "$tag" --cleanup-tag --yes 2>/dev/null || true
|
|
80
|
+
gh release create "$tag" dist/* --prerelease --target "$GITHUB_SHA" \
|
|
81
|
+
--title "Daily build ${{ steps.check.outputs.day }} ($version)" --notes-file notes.md
|
|
82
|
+
|
|
83
|
+
- name: Keep only the last 14 daily builds
|
|
84
|
+
if: steps.check.outputs.skip == 'false'
|
|
85
|
+
run: |
|
|
86
|
+
gh release list --limit 200 --json tagName,createdAt \
|
|
87
|
+
-q '[.[] | select(.tagName | startswith("daily-"))] | sort_by(.createdAt) | reverse | .[14:] | .[].tagName' |
|
|
88
|
+
while read -r old; do
|
|
89
|
+
gh release delete "$old" --cleanup-tag --yes
|
|
90
|
+
done
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Release: run by hand (Actions tab -> Release -> Run workflow, or
|
|
2
|
+
# `gh workflow run release.yml -f bump=minor`). Tags the current main as
|
|
3
|
+
# the next version, builds it, and publishes it as a GitHub release. The
|
|
4
|
+
# package-manager channels (PyPI, Homebrew, apt, ...) hang off the end of
|
|
5
|
+
# this as they're added. See docs/releasing.md.
|
|
6
|
+
name: Release
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
bump:
|
|
12
|
+
description: Which part of the version to bump
|
|
13
|
+
type: choice
|
|
14
|
+
options: [minor, patch, major]
|
|
15
|
+
default: minor
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: write
|
|
19
|
+
|
|
20
|
+
concurrency: release
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
release:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
env:
|
|
26
|
+
GH_TOKEN: ${{ github.token }}
|
|
27
|
+
outputs:
|
|
28
|
+
version: ${{ steps.version.outputs.version }}
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 0
|
|
33
|
+
|
|
34
|
+
- name: Next version
|
|
35
|
+
id: version
|
|
36
|
+
run: |
|
|
37
|
+
previous=$(git describe --tags --abbrev=0 --match 'v[0-9]*')
|
|
38
|
+
if [ -n "$(git tag --points-at HEAD --list 'v[0-9]*')" ]; then
|
|
39
|
+
echo "::error::main is already released as $previous — nothing new to release."
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
IFS=. read -r major minor patch <<< "${previous#v}"
|
|
43
|
+
case "${{ inputs.bump }}" in
|
|
44
|
+
major) version="$((major + 1)).0.0" ;;
|
|
45
|
+
minor) version="$major.$((minor + 1)).0" ;;
|
|
46
|
+
patch) version="$major.$minor.$((patch + 1))" ;;
|
|
47
|
+
esac
|
|
48
|
+
echo "Releasing $version (previous: $previous)"
|
|
49
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
50
|
+
echo "previous=$previous" >> "$GITHUB_OUTPUT"
|
|
51
|
+
|
|
52
|
+
- name: Tag
|
|
53
|
+
run: |
|
|
54
|
+
git config user.name "github-actions[bot]"
|
|
55
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
56
|
+
git tag -a "v${{ steps.version.outputs.version }}" -m "takeloom ${{ steps.version.outputs.version }}"
|
|
57
|
+
|
|
58
|
+
- uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.12"
|
|
61
|
+
|
|
62
|
+
- name: Build
|
|
63
|
+
run: |
|
|
64
|
+
python -m pip install --quiet build
|
|
65
|
+
python -m build
|
|
66
|
+
ls dist
|
|
67
|
+
# The tag must have produced exactly this version, not a .dev one.
|
|
68
|
+
test -f "dist/takeloom-${{ steps.version.outputs.version }}-py3-none-any.whl"
|
|
69
|
+
|
|
70
|
+
- name: Smoke test
|
|
71
|
+
run: |
|
|
72
|
+
sudo apt-get update -qq && sudo apt-get install -y -qq libportaudio2 libsndfile1
|
|
73
|
+
python -m pip install --quiet dist/*.whl
|
|
74
|
+
takeloom --help
|
|
75
|
+
|
|
76
|
+
- name: Push tag and publish release
|
|
77
|
+
run: |
|
|
78
|
+
version="${{ steps.version.outputs.version }}"
|
|
79
|
+
previous="${{ steps.version.outputs.previous }}"
|
|
80
|
+
git push origin "v$version"
|
|
81
|
+
{
|
|
82
|
+
echo "### Changes since $previous"
|
|
83
|
+
git log --format='- %s (%h)' "$previous..HEAD"
|
|
84
|
+
} > notes.md
|
|
85
|
+
gh release create "v$version" dist/* --latest --title "takeloom $version" --notes-file notes.md
|
|
86
|
+
|
|
87
|
+
- uses: actions/upload-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
name: dist
|
|
90
|
+
path: dist/
|
|
91
|
+
|
|
92
|
+
pypi:
|
|
93
|
+
# Trusted publishing: PyPI's takeloom project trusts this repo's
|
|
94
|
+
# release.yml in the "pypi" environment, so no token is stored anywhere.
|
|
95
|
+
needs: release
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
environment:
|
|
98
|
+
name: pypi
|
|
99
|
+
url: https://pypi.org/project/takeloom/${{ needs.release.outputs.version }}/
|
|
100
|
+
permissions:
|
|
101
|
+
id-token: write
|
|
102
|
+
steps:
|
|
103
|
+
- uses: actions/download-artifact@v4
|
|
104
|
+
with:
|
|
105
|
+
name: dist
|
|
106
|
+
path: dist/
|
|
107
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
dist/
|
|
5
|
+
build/
|
|
6
|
+
*.egg
|
|
7
|
+
.eggs/
|
|
8
|
+
*.flac
|
|
9
|
+
*.wav
|
|
10
|
+
!takeloom/data/measure_latency.wav
|
|
11
|
+
*.mp3
|
|
12
|
+
*.m4a
|
|
13
|
+
.env
|
|
14
|
+
|
|
15
|
+
# Takeloom Camera app build output (camera_app/)
|
|
16
|
+
camera_app/ios/TakeloomCamera.xcodeproj/
|
|
17
|
+
camera_app/android/.gradle/
|
|
18
|
+
camera_app/android/local.properties
|
|
19
|
+
camera_app/android/app/build/
|
|
20
|
+
.DS_Store
|
takeloom-0.5.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Deployment
|
|
2
|
+
|
|
3
|
+
Always push every commit to `origin` (`main`) right after making it — no need to ask first. This is a standing authorization for `git push` specifically in this repo; it doesn't extend to other destructive/shared-state git operations (force-push, reset --hard, etc.), which still need confirmation as usual.
|
|
4
|
+
|
|
5
|
+
There are two machines running `takeloom`, installed differently:
|
|
6
|
+
|
|
7
|
+
- The laptop ("Framework"), reachable via `ssh framework` (non-interactive/key-auth works). Installed via `pipx` directly from this GitHub repo (`takeloom @ git+https://github.com/priestc/takeloom.git`) — not an editable clone, so picking up new code requires a reinstall, not a `git pull`.
|
|
8
|
+
- The Mac Mini — the studio hub machine with the Scarlett 4i4 attached (see `studio_hardware_scarlett_4i4` memory), and normally the machine Claude Code itself is already running on (`hostname` reports `Mac.local`). Installed via `pipx install --editable ~/Documents/GitHub/takeloom` — an editable install pointing straight at this working copy (confirm with `cat ~/.local/pipx/venvs/takeloom/lib/python*/site-packages/takeloom*.dist-info/direct_url.json`, should show `"editable": true`). Any commit — or even an uncommitted local edit — takes effect the next time `takeloom` is launched there; no reinstall step needed. (If a dependency is ever added/changed in `pyproject.toml`, that *does* still need `pipx install --editable --force ~/Documents/GitHub/takeloom` to pick up the new package.)
|
|
9
|
+
|
|
10
|
+
Any change **except code that only affects server mode** (i.e. changes confined to the headless `takeloom server` path — see `takeloom/__main__.py`'s `server_command` and anything only reachable from it) should be automatically deployed once committed:
|
|
11
|
+
|
|
12
|
+
1. Push to `origin` (`main`). That's the only step to take here — do not `ssh framework` to reinstall.
|
|
13
|
+
2. The laptop no longer gets deployed to manually. `takeloom ui` checks GitHub's `main` on launch and self-updates (reinstalls + restarts) if it's behind — see `takeloom/update_check.py`. The user's habit is to close and reopen the app on the laptop before testing, which is what actually picks up the new commit; nothing needs to happen on the laptop from this side beyond the push.
|
|
14
|
+
3. Nothing further needed for the Mac Mini — just make sure `takeloom` (or `takeloom server`) is restarted there to pick up the change.
|
|
15
|
+
|
|
16
|
+
Manual laptop reinstall (reference only — for troubleshooting if auto-update ever fails or misbehaves, not part of the normal flow above):
|
|
17
|
+
`ssh framework "pipx install --force git+https://github.com/priestc/takeloom.git"`
|
|
18
|
+
|
|
19
|
+
# Testing setup
|
|
20
|
+
|
|
21
|
+
- All actual hardware — audio interfaces (the Scarlett 4i4) and the Stream Deck — is attached to the **Mac Mini**, and only the Mac Mini ever runs `takeloom server` or performs an actual recording. Nothing is ever plugged into the laptop.
|
|
22
|
+
- The **laptop ("Framework")** only ever runs `takeloom` in remote mode — connecting to the Mac Mini's `takeloom server` via the Remote tab / `--remote=IP` — to control a session running on the Mac Mini. It never has a device attached and a recording is never started or written locally on it, so the CLI recording paths (`start-session`, `inspiration`) are effectively unused/untested there in practice; treat bugs reported "on the laptop" as remote-mode bugs first.
|
|
23
|
+
- The laptop sleeps whenever it's unplugged, which is its normal state (it's rarely plugged in). Keep this in mind for anything that assumes it stays awake/reachable — e.g. it can drop off the network mid-session, and any "don't sleep while recording" behavior only matters there for the remote-viewing UI, not a local recording session.
|
|
24
|
+
- On the Mac Mini, the Scarlett 4i4 and Stream Deck are usually powered off between sessions. You're allowed to launch `takeloom ui` there to visually verify pure-UI changes (screenshot it, check it looks right, close it) — no need to ask first. It's expected and fine for audio devices/instrument meters/the Stream Deck connection to show empty or disconnected in that state; that's not a bug, just means the hardware happens to be off right now. Don't read anything into it unless the change you're testing is specifically about device detection/connection.
|
takeloom-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chris Priest
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
takeloom-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: takeloom
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Music Recording Session Manager
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Requires-Dist: click>=8.0
|
|
9
|
+
Requires-Dist: mido>=1.3.0
|
|
10
|
+
Requires-Dist: numpy>=1.24.0
|
|
11
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
12
|
+
Requires-Dist: pillow>=9.0.0
|
|
13
|
+
Requires-Dist: pyfluidsynth>=1.3.2
|
|
14
|
+
Requires-Dist: python-rtmidi>=1.5.0; sys_platform == 'darwin'
|
|
15
|
+
Requires-Dist: pyusb>=1.2.1
|
|
16
|
+
Requires-Dist: sounddevice>=0.4.6
|
|
17
|
+
Requires-Dist: soundfile>=0.12.1
|
|
18
|
+
Requires-Dist: static-ffmpeg>=2.5
|
|
19
|
+
Requires-Dist: streamdeck>=0.9.0
|
|
20
|
+
Requires-Dist: tkinterdnd2>=0.3.0
|
|
21
|
+
Requires-Dist: wakepy>=0.7.0
|
takeloom-0.5.0/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Takeloom
|
|
2
|
+
|
|
3
|
+
A CLI application for musicians to record instruments over backing tracks, manage songs/albums, and track completed takes.
|
|
4
|
+
|
|
5
|
+
Takeloom handles continuous audio recording, playback mixing, session logging, and per-take file management. Record one instrument at a time — each new session plays back your previous takes alongside the backing track so you can layer parts.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Python 3.9+
|
|
10
|
+
- PortAudio, libsndfile, ffmpeg (system libraries)
|
|
11
|
+
- yt-dlp (optional, system binary) — only needed to add YouTube URLs as backing tracks from the New Project dialog
|
|
12
|
+
|
|
13
|
+
See [Prerequisites](docs/prerequisites.md) for install instructions for each operating system.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pipx install takeloom
|
|
19
|
+
takeloom install-launcher
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
That's the latest release from PyPI. To follow every commit on `main`
|
|
23
|
+
instead (and auto-update to it on each launch):
|
|
24
|
+
`pipx install git+https://github.com/priestc/takeloom.git`
|
|
25
|
+
|
|
26
|
+
`takeloom install-launcher` adds Takeloom to the Applications folder
|
|
27
|
+
(macOS) or to the applications menu and desktop (Linux), so the UI opens
|
|
28
|
+
like any other app. Updates still go through pipx, automatically, each
|
|
29
|
+
time the UI opens.
|
|
30
|
+
|
|
31
|
+
**macOS, drag-to-install:** `python3 scripts/build_macos_dmg.py` builds
|
|
32
|
+
`dist/Takeloom.dmg`. Drag Takeloom into Applications. On first open the app
|
|
33
|
+
installs takeloom with pipx (Homebrew's `pipx` and `python-tk` must already
|
|
34
|
+
be installed). An app that came from a download is blocked the first time,
|
|
35
|
+
since it isn't signed by Apple: right-click it and choose Open.
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
### Studio Setup
|
|
40
|
+
|
|
41
|
+
Configure your studio in three steps. Each command reads and updates `~/studio_config.json` independently, so you can re-run one without redoing the others.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
takeloom setup-studio # studio name, location, musician, remote vault server
|
|
45
|
+
takeloom setup-recording-devices # sample rate, buffer size, output device, input labels, camera
|
|
46
|
+
takeloom setup-instruments # assign instruments to input channels
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`setup-recording-devices` also lets you pick a camera. If one is configured, every session
|
|
50
|
+
records video alongside the audio (see [Recording Session](#recording-session)).
|
|
51
|
+
|
|
52
|
+
`setup-studio` also configures the **Studio Session Vault** — shared storage for everything
|
|
53
|
+
a project used to keep to itself: recorded sessions, backing tracks, and completed takes
|
|
54
|
+
(see [Project Structure](#project-structure)). A project is just a setlist file now. Three
|
|
55
|
+
vault modes: local only (default, under `~/Documents`), remote only (uploaded to the remote
|
|
56
|
+
vault server and removed locally once every file's checksum is verified), or both (uploaded
|
|
57
|
+
but also kept locally). Starting a session downloads whatever that project's setlist needs
|
|
58
|
+
from the remote first, in remote-only mode.
|
|
59
|
+
|
|
60
|
+
The remote vault is a separate small server, `takeloom-vault` (this repo's
|
|
61
|
+
[`vault_server/`](vault_server/README.md) folder), running on the storage machine. It also
|
|
62
|
+
serves a web page for browsing sessions and watching their videos. Takeloom pairs with it
|
|
63
|
+
the same way Remote mode pairs: click **Pair...** next to "Remote vault server" in Studio
|
|
64
|
+
Setup (or run `takeloom vault pair tank2`), then approve the code shown on the vault's web
|
|
65
|
+
page. `takeloom vault status` checks the connection. If you have projects from before the vault existed, run
|
|
66
|
+
`takeloom migrate-sessions-to-vault` once to move everything in — safe to re-run,
|
|
67
|
+
already-migrated projects are skipped.
|
|
68
|
+
|
|
69
|
+
### Graphical Interface
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
takeloom ui
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Opens a desktop window (built with tkinter). Currently implements the Studio Setup screen —
|
|
76
|
+
the same fields as `takeloom setup-studio` — with more screens to follow.
|
|
77
|
+
|
|
78
|
+
### Creating a Project
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
takeloom new-project
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Enter a project name (e.g. "My Album"). Creates `~/Takeloom Projects/My Album.json` — an
|
|
85
|
+
empty setlist.
|
|
86
|
+
|
|
87
|
+
### Updating the Setlist
|
|
88
|
+
|
|
89
|
+
Copy audio files (FLAC, WAV, MP3, M4A) into the vault's `backing_tracks/` directory, then:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
takeloom update-setlist "My Album"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Adds any of the vault's backing tracks not yet in this project's setlist (omit the project
|
|
96
|
+
name to use the last-used project). Each track in the setlist includes a `volume` field
|
|
97
|
+
(default 100%) that you can edit manually to adjust backing track playback level.
|
|
98
|
+
|
|
99
|
+
### Recording Session
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
takeloom start-session guitar "My Album"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The session plays the backing track through your speakers, monitors your instrument input in real-time, and records your take. Controls:
|
|
106
|
+
|
|
107
|
+
| Key | Action | When |
|
|
108
|
+
|-----|--------|------|
|
|
109
|
+
| `r` | Start recording (plays backing track) | Waiting |
|
|
110
|
+
| `b` | Back to start (restart the take) | Playing |
|
|
111
|
+
| `e` | Mark song end (complete the take) | Playing |
|
|
112
|
+
| `n` | Move to next track (auto-starts recording) | Between tracks |
|
|
113
|
+
| `l` | Lower backing track volume by 5% | Any time |
|
|
114
|
+
| `u` | Raise backing track volume by 5% | Any time |
|
|
115
|
+
| `q` | End session | Any time |
|
|
116
|
+
|
|
117
|
+
**Completing a take:** Press `r` to start, then `e` when the song finishes. The take is saved to the vault's `completed_takes/` and set as the preferred take in the setlist.
|
|
118
|
+
|
|
119
|
+
**Restarting a take:** Press `b` to loop back to the beginning. The backing track restarts and a new take file begins.
|
|
120
|
+
|
|
121
|
+
**Volume adjustments** are saved back to the setlist file at the end of the session.
|
|
122
|
+
|
|
123
|
+
**Video:** if a camera is configured (`takeloom setup-recording-devices`), the whole session is
|
|
124
|
+
also recorded on video, saved as `session_video.mp4` alongside `session.flac` once the session
|
|
125
|
+
ends. The video has two audio tracks: a compressed (AAC) mix of the backing track + your
|
|
126
|
+
instrument for easy playback, and a lossless (FLAC) track of just your instrument alone.
|
|
127
|
+
|
|
128
|
+
### Multi-Instrument Layering
|
|
129
|
+
|
|
130
|
+
Start a new session with a different instrument (e.g. "bass"). The backing track plays mixed with your previously recorded preferred takes, so you hear everything together while recording the new part.
|
|
131
|
+
|
|
132
|
+
### Desktop Audio Capture
|
|
133
|
+
|
|
134
|
+
To record virtual instruments, software synths, or system audio, you need a virtual audio loopback device. See [Desktop Audio Capture Setup](docs/desktop-audio-capture.md) for instructions.
|
|
135
|
+
|
|
136
|
+
### Live Streaming
|
|
137
|
+
|
|
138
|
+
The GUI's Streaming tab can push every session live to YouTube over RTMP — just paste a
|
|
139
|
+
stream key from YouTube Studio and enable it. Connecting a YouTube account is optional
|
|
140
|
+
and only needed if you also want each session's stream auto-titled with the studio,
|
|
141
|
+
musician, project, and date; that requires creating your own free Google Cloud OAuth
|
|
142
|
+
credentials. See [YouTube Streaming Setup](docs/youtube-streaming-setup.md) for the
|
|
143
|
+
steps, and why it can't just be a one-click sign-in.
|
|
144
|
+
|
|
145
|
+
## Project Structure
|
|
146
|
+
|
|
147
|
+
A project is just a setlist file — `<projects_dir>/My Album.json`. Everything else lives in
|
|
148
|
+
the shared Studio Session Vault (see [Studio Setup](#studio-setup)) instead of belonging to
|
|
149
|
+
one project, so two different projects can reference the same backing track or completed
|
|
150
|
+
take (most commonly a song pulled in from the Inspiration library — see
|
|
151
|
+
[Cross-Project Take Reuse](#cross-project-take-reuse)) without either downloading or
|
|
152
|
+
recording it twice:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
<projects_dir>/
|
|
156
|
+
├── My Album.json
|
|
157
|
+
└── Side Project.json
|
|
158
|
+
|
|
159
|
+
<vault>/
|
|
160
|
+
├── backing_tracks/
|
|
161
|
+
│ ├── song1.mp3
|
|
162
|
+
│ └── a1b2c3d4_song2.flac
|
|
163
|
+
├── completed_takes/
|
|
164
|
+
│ ├── song1 - guitar - take1 [upload:a1b2c3d4].flac
|
|
165
|
+
│ ├── song1 - bass - take1 [upload:a1b2c3d4].flac
|
|
166
|
+
│ └── song2 - guitar - take2 [youtube:dQw4w9WgXcQ].flac
|
|
167
|
+
├── inspiration_takes.json
|
|
168
|
+
└── sessions/
|
|
169
|
+
└── 2025-01-15_14-30-00_guitar_My Album/
|
|
170
|
+
├── session.flac
|
|
171
|
+
├── session_video.mp4
|
|
172
|
+
└── session_log.json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- `backing_tracks/` and `completed_takes/` are shared across every project. A locally
|
|
176
|
+
uploaded file gets a short random prefix added only if its plain name would otherwise
|
|
177
|
+
collide with an unrelated project's file; a file that already has a globally unique name
|
|
178
|
+
(a YouTube download, or one pulled from the Inspiration library) keeps it as-is.
|
|
179
|
+
- A completed take's filename tags the exact backing track it was recorded against —
|
|
180
|
+
`[upload:<id>]`, `[youtube:<video id>]`, or `[inspiration:<track id>]` — since backing
|
|
181
|
+
tracks are shared vault-wide now and two entries can share a display name while pointing
|
|
182
|
+
at different audio.
|
|
183
|
+
- Existing take files are never deleted. New takes increment the take number and replace the preferred take in the setlist.
|
|
184
|
+
- `inspiration_takes.json` — the cross-project take index (see below).
|
|
185
|
+
- `session.flac` — the continuous raw recording spanning the full session
|
|
186
|
+
- `session_log.json` — musician, studio, and event data; what post-session processing replays to find completed takes and copy them into the vault's `completed_takes/`
|
|
187
|
+
- `session_video.mp4` is only present when a camera is configured
|
|
188
|
+
|
|
189
|
+
### Cross-Project Take Reuse
|
|
190
|
+
|
|
191
|
+
A song pulled from the Inspiration library carries a stable ID from that library, so a take
|
|
192
|
+
recorded on it from *any* project is recorded into `inspiration_takes.json` too, keyed by
|
|
193
|
+
that ID. This is what lets an "inspiration filter" setlist slot (a standing "draw a random
|
|
194
|
+
song from this filter each session" entry — added from the GUI's Streaming/Setlist screens)
|
|
195
|
+
prefer redrawing a song other instruments already have a take on, and what lets
|
|
196
|
+
`ensure_setlist_files_local` (session start, in remote vault mode) pull down another
|
|
197
|
+
project's take on a shared song before it's needed.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT — see [LICENSE](LICENSE). Builds and releases: [docs/releasing.md](docs/releasing.md).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id("com.android.application")
|
|
3
|
+
id("org.jetbrains.kotlin.android")
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
android {
|
|
7
|
+
namespace = "com.priestc.takeloomcamera"
|
|
8
|
+
compileSdk = 34
|
|
9
|
+
|
|
10
|
+
defaultConfig {
|
|
11
|
+
applicationId = "com.priestc.takeloomcamera"
|
|
12
|
+
// 29: MediaFormat.KEY_MAX_B_FRAMES, and AudioRecord timestamps on
|
|
13
|
+
// the boot-time clock camera sensors often use.
|
|
14
|
+
minSdk = 29
|
|
15
|
+
targetSdk = 34
|
|
16
|
+
versionCode = 1
|
|
17
|
+
versionName = "1.0"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
buildTypes {
|
|
21
|
+
release {
|
|
22
|
+
isMinifyEnabled = false
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
compileOptions {
|
|
26
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
27
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
28
|
+
}
|
|
29
|
+
kotlinOptions {
|
|
30
|
+
jvmTarget = "17"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
|
|
4
|
+
<uses-feature android:name="android.hardware.camera.any" android:required="true" />
|
|
5
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
6
|
+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
7
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
8
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
9
|
+
|
|
10
|
+
<application
|
|
11
|
+
android:allowBackup="false"
|
|
12
|
+
android:icon="@mipmap/ic_launcher"
|
|
13
|
+
android:label="@string/app_name"
|
|
14
|
+
android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen">
|
|
15
|
+
<activity
|
|
16
|
+
android:name=".MainActivity"
|
|
17
|
+
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
|
|
18
|
+
android:exported="true"
|
|
19
|
+
android:screenOrientation="sensorLandscape">
|
|
20
|
+
<intent-filter>
|
|
21
|
+
<action android:name="android.intent.action.MAIN" />
|
|
22
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
23
|
+
</intent-filter>
|
|
24
|
+
</activity>
|
|
25
|
+
</application>
|
|
26
|
+
</manifest>
|