fourier-samples 0.1.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.
- fourier_samples-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
- fourier_samples-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- fourier_samples-0.1.0/.github/ISSUE_TEMPLATE/device_request.yml +46 -0
- fourier_samples-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +21 -0
- fourier_samples-0.1.0/.github/dependabot.yml +11 -0
- fourier_samples-0.1.0/.github/pull_request_template.md +13 -0
- fourier_samples-0.1.0/.github/workflows/ci.yml +128 -0
- fourier_samples-0.1.0/.github/workflows/release.yml +64 -0
- fourier_samples-0.1.0/.gitignore +18 -0
- fourier_samples-0.1.0/AGENTS.md +13 -0
- fourier_samples-0.1.0/CHANGELOG.md +125 -0
- fourier_samples-0.1.0/CLAUDE.md +355 -0
- fourier_samples-0.1.0/CODE_OF_CONDUCT.md +134 -0
- fourier_samples-0.1.0/CONTRIBUTING.md +93 -0
- fourier_samples-0.1.0/LICENSE +202 -0
- fourier_samples-0.1.0/NOTICE +10 -0
- fourier_samples-0.1.0/PKG-INFO +327 -0
- fourier_samples-0.1.0/README.md +273 -0
- fourier_samples-0.1.0/SECURITY.md +39 -0
- fourier_samples-0.1.0/THIRD_PARTY_NOTICES.md +60 -0
- fourier_samples-0.1.0/config/devices/digitakt_2.yaml +90 -0
- fourier_samples-0.1.0/config/devices/generic_44k.yaml +21 -0
- fourier_samples-0.1.0/config/devices/generic_48k.yaml +21 -0
- fourier_samples-0.1.0/config/devices/generic_folder.yaml +21 -0
- fourier_samples-0.1.0/config/devices/generic_sd_card.yaml +25 -0
- fourier_samples-0.1.0/config/devices/m8_tracker.yaml +118 -0
- fourier_samples-0.1.0/config/presets/ambient-cinematic.yaml +35 -0
- fourier_samples-0.1.0/config/presets/balanced.yaml +12 -0
- fourier_samples-0.1.0/config/presets/breaks-acid.yaml +16 -0
- fourier_samples-0.1.0/config/presets/hiphop-lofi.yaml +29 -0
- fourier_samples-0.1.0/config/presets/house-techno.yaml +26 -0
- fourier_samples-0.1.0/config/presets/trap.yaml +30 -0
- fourier_samples-0.1.0/config/providers/path.yaml +60 -0
- fourier_samples-0.1.0/config/providers/sononym.yaml +36 -0
- fourier_samples-0.1.0/config/taxonomy.yaml +711 -0
- fourier_samples-0.1.0/config/tunables.yaml +388 -0
- fourier_samples-0.1.0/conftest.py +138 -0
- fourier_samples-0.1.0/docs/curation.md +977 -0
- fourier_samples-0.1.0/docs/design-history.md +58 -0
- fourier_samples-0.1.0/docs/device-profiles.md +174 -0
- fourier_samples-0.1.0/docs/guide.md +167 -0
- fourier_samples-0.1.0/docs/start.md +316 -0
- fourier_samples-0.1.0/docs/usage.md +322 -0
- fourier_samples-0.1.0/pyproject.toml +100 -0
- fourier_samples-0.1.0/scripts/capture_demo.py +59 -0
- fourier_samples-0.1.0/scripts/golden_compare.py +46 -0
- fourier_samples-0.1.0/scripts/golden_harness.py +268 -0
- fourier_samples-0.1.0/scripts/manifest_diff.py +20 -0
- fourier_samples-0.1.0/scripts/provider_report.py +161 -0
- fourier_samples-0.1.0/scripts/render_audit.py +71 -0
- fourier_samples-0.1.0/scripts/tunables_inventory.py +117 -0
- fourier_samples-0.1.0/src/fourier/__init__.py +28 -0
- fourier_samples-0.1.0/src/fourier/__main__.py +5 -0
- fourier_samples-0.1.0/src/fourier/analysis/__init__.py +14 -0
- fourier_samples-0.1.0/src/fourier/analysis/clap_features.py +442 -0
- fourier_samples-0.1.0/src/fourier/analysis/derived.py +248 -0
- fourier_samples-0.1.0/src/fourier/analysis/events.py +92 -0
- fourier_samples-0.1.0/src/fourier/analysis/key_detection.py +103 -0
- fourier_samples-0.1.0/src/fourier/analysis/librosa_features.py +257 -0
- fourier_samples-0.1.0/src/fourier/analysis/loop_trim.py +215 -0
- fourier_samples-0.1.0/src/fourier/analysis/resolution.py +70 -0
- fourier_samples-0.1.0/src/fourier/cli/__init__.py +24 -0
- fourier_samples-0.1.0/src/fourier/cli/__main__.py +3 -0
- fourier_samples-0.1.0/src/fourier/cli/_app.py +298 -0
- fourier_samples-0.1.0/src/fourier/cli/build.py +1403 -0
- fourier_samples-0.1.0/src/fourier/cli/config.py +317 -0
- fourier_samples-0.1.0/src/fourier/cli/db.py +305 -0
- fourier_samples-0.1.0/src/fourier/cli/devices.py +300 -0
- fourier_samples-0.1.0/src/fourier/cli/enrich.py +1604 -0
- fourier_samples-0.1.0/src/fourier/cli/ingest.py +267 -0
- fourier_samples-0.1.0/src/fourier/cli/opener.py +97 -0
- fourier_samples-0.1.0/src/fourier/cli/quiet.py +204 -0
- fourier_samples-0.1.0/src/fourier/cli/releases.py +582 -0
- fourier_samples-0.1.0/src/fourier/cli/review.py +271 -0
- fourier_samples-0.1.0/src/fourier/cli/search.py +513 -0
- fourier_samples-0.1.0/src/fourier/cli/setup.py +1957 -0
- fourier_samples-0.1.0/src/fourier/db/__init__.py +0 -0
- fourier_samples-0.1.0/src/fourier/db/migrations.py +131 -0
- fourier_samples-0.1.0/src/fourier/db/models.py +552 -0
- fourier_samples-0.1.0/src/fourier/db/session.py +307 -0
- fourier_samples-0.1.0/src/fourier/demo.py +384 -0
- fourier_samples-0.1.0/src/fourier/devices/__init__.py +0 -0
- fourier_samples-0.1.0/src/fourier/devices/convert.py +104 -0
- fourier_samples-0.1.0/src/fourier/devices/exporter.py +305 -0
- fourier_samples-0.1.0/src/fourier/devices/loader.py +399 -0
- fourier_samples-0.1.0/src/fourier/ingest/__init__.py +0 -0
- fourier_samples-0.1.0/src/fourier/ingest/ableton_tags.py +155 -0
- fourier_samples-0.1.0/src/fourier/ingest/chunks.py +92 -0
- fourier_samples-0.1.0/src/fourier/ingest/folder.py +159 -0
- fourier_samples-0.1.0/src/fourier/ingest/formats.py +65 -0
- fourier_samples-0.1.0/src/fourier/ingest/importer.py +802 -0
- fourier_samples-0.1.0/src/fourier/ingest/sononym.py +766 -0
- fourier_samples-0.1.0/src/fourier/ingest/walk.py +285 -0
- fourier_samples-0.1.0/src/fourier/knobs.py +559 -0
- fourier_samples-0.1.0/src/fourier/layers.py +400 -0
- fourier_samples-0.1.0/src/fourier/metadata/__init__.py +1 -0
- fourier_samples-0.1.0/src/fourier/metadata/providers.py +98 -0
- fourier_samples-0.1.0/src/fourier/metadata/resolve.py +357 -0
- fourier_samples-0.1.0/src/fourier/metadata/rows.py +519 -0
- fourier_samples-0.1.0/src/fourier/metadata/shadow.py +396 -0
- fourier_samples-0.1.0/src/fourier/metadata/sound.py +613 -0
- fourier_samples-0.1.0/src/fourier/metadata/store.py +208 -0
- fourier_samples-0.1.0/src/fourier/metadata/train.py +706 -0
- fourier_samples-0.1.0/src/fourier/metadata/vocab.py +52 -0
- fourier_samples-0.1.0/src/fourier/net.py +15 -0
- fourier_samples-0.1.0/src/fourier/packs/__init__.py +0 -0
- fourier_samples-0.1.0/src/fourier/packs/audiocache.py +175 -0
- fourier_samples-0.1.0/src/fourier/packs/audit.py +169 -0
- fourier_samples-0.1.0/src/fourier/packs/builddiff.py +225 -0
- fourier_samples-0.1.0/src/fourier/packs/curate.py +5550 -0
- fourier_samples-0.1.0/src/fourier/packs/curate_config.py +1233 -0
- fourier_samples-0.1.0/src/fourier/packs/device_lock.py +236 -0
- fourier_samples-0.1.0/src/fourier/packs/dryrun.py +131 -0
- fourier_samples-0.1.0/src/fourier/packs/golden.py +172 -0
- fourier_samples-0.1.0/src/fourier/packs/naming.py +685 -0
- fourier_samples-0.1.0/src/fourier/packs/progress.py +118 -0
- fourier_samples-0.1.0/src/fourier/packs/ratings.py +950 -0
- fourier_samples-0.1.0/src/fourier/packs/releases.py +467 -0
- fourier_samples-0.1.0/src/fourier/packs/render.py +687 -0
- fourier_samples-0.1.0/src/fourier/packs/report.py +209 -0
- fourier_samples-0.1.0/src/fourier/packs/review.py +300 -0
- fourier_samples-0.1.0/src/fourier/packs/rules.py +465 -0
- fourier_samples-0.1.0/src/fourier/packs/scale.py +123 -0
- fourier_samples-0.1.0/src/fourier/packs/sets.py +381 -0
- fourier_samples-0.1.0/src/fourier/packs/validate.py +186 -0
- fourier_samples-0.1.0/src/fourier/packs/vendors.py +238 -0
- fourier_samples-0.1.0/src/fourier/packs/verify.py +1073 -0
- fourier_samples-0.1.0/src/fourier/packs/why.py +566 -0
- fourier_samples-0.1.0/src/fourier/packs/why_log.py +212 -0
- fourier_samples-0.1.0/src/fourier/paths.py +52 -0
- fourier_samples-0.1.0/src/fourier/places.py +319 -0
- fourier_samples-0.1.0/src/fourier/platforms.py +308 -0
- fourier_samples-0.1.0/src/fourier/preparers.py +141 -0
- fourier_samples-0.1.0/src/fourier/safety.py +477 -0
- fourier_samples-0.1.0/src/fourier/settings.py +195 -0
- fourier_samples-0.1.0/src/fourier/synthlib.py +324 -0
- fourier_samples-0.1.0/src/fourier/taxonomy.py +335 -0
- fourier_samples-0.1.0/src/fourier/timings.py +173 -0
- fourier_samples-0.1.0/tests/__init__.py +0 -0
- fourier_samples-0.1.0/tests/data/cli_tree.json +3056 -0
- fourier_samples-0.1.0/tests/data/schema_v1/duckdb.sql +26 -0
- fourier_samples-0.1.0/tests/data/schema_v1/sqlite.sql +168 -0
- fourier_samples-0.1.0/tests/data/tunables_snapshot.json +8254 -0
- fourier_samples-0.1.0/tests/golden/synthetic-darwin.json +6851 -0
- fourier_samples-0.1.0/tests/golden/synthetic-linux.json +6851 -0
- fourier_samples-0.1.0/tests/golden/synthetic.toml +9 -0
- fourier_samples-0.1.0/tests/golden/synthetic_build.py +349 -0
- fourier_samples-0.1.0/tests/regressions/__init__.py +0 -0
- fourier_samples-0.1.0/tests/regressions/test_curate_regressions.py +274 -0
- fourier_samples-0.1.0/tests/regressions/test_ratings_regressions.py +236 -0
- fourier_samples-0.1.0/tests/regressions/test_releases_regressions.py +495 -0
- fourier_samples-0.1.0/tests/regressions/test_render_regressions.py +179 -0
- fourier_samples-0.1.0/tests/test_added_categories.py +144 -0
- fourier_samples-0.1.0/tests/test_analyze_selection.py +70 -0
- fourier_samples-0.1.0/tests/test_audiocache.py +109 -0
- fourier_samples-0.1.0/tests/test_audit_fixes.py +167 -0
- fourier_samples-0.1.0/tests/test_budget.py +119 -0
- fourier_samples-0.1.0/tests/test_builddiff.py +102 -0
- fourier_samples-0.1.0/tests/test_canonical_mapping.py +151 -0
- fourier_samples-0.1.0/tests/test_clap_offline.py +207 -0
- fourier_samples-0.1.0/tests/test_cli_tree.py +61 -0
- fourier_samples-0.1.0/tests/test_cloud_only.py +295 -0
- fourier_samples-0.1.0/tests/test_copies_and_moves_cli.py +121 -0
- fourier_samples-0.1.0/tests/test_curate.py +405 -0
- fourier_samples-0.1.0/tests/test_db.py +250 -0
- fourier_samples-0.1.0/tests/test_demo.py +141 -0
- fourier_samples-0.1.0/tests/test_device_citations.py +149 -0
- fourier_samples-0.1.0/tests/test_device_lock.py +166 -0
- fourier_samples-0.1.0/tests/test_device_profiles_user.py +252 -0
- fourier_samples-0.1.0/tests/test_events.py +96 -0
- fourier_samples-0.1.0/tests/test_export.py +148 -0
- fourier_samples-0.1.0/tests/test_fallback_routing.py +286 -0
- fourier_samples-0.1.0/tests/test_fallback_routing_cli.py +227 -0
- fourier_samples-0.1.0/tests/test_first_run.py +591 -0
- fourier_samples-0.1.0/tests/test_golden.py +181 -0
- fourier_samples-0.1.0/tests/test_golden_harness.py +185 -0
- fourier_samples-0.1.0/tests/test_guards_cli.py +376 -0
- fourier_samples-0.1.0/tests/test_instrument_cap.py +17 -0
- fourier_samples-0.1.0/tests/test_keys_routing.py +69 -0
- fourier_samples-0.1.0/tests/test_knobs.py +216 -0
- fourier_samples-0.1.0/tests/test_layers.py +188 -0
- fourier_samples-0.1.0/tests/test_library_walk.py +503 -0
- fourier_samples-0.1.0/tests/test_metadata_store.py +101 -0
- fourier_samples-0.1.0/tests/test_migrations.py +28 -0
- fourier_samples-0.1.0/tests/test_missing_library.py +225 -0
- fourier_samples-0.1.0/tests/test_naming.py +254 -0
- fourier_samples-0.1.0/tests/test_net.py +12 -0
- fourier_samples-0.1.0/tests/test_newcomer.py +223 -0
- fourier_samples-0.1.0/tests/test_other_libraries.py +285 -0
- fourier_samples-0.1.0/tests/test_other_libraries_cli.py +180 -0
- fourier_samples-0.1.0/tests/test_paths.py +92 -0
- fourier_samples-0.1.0/tests/test_places.py +126 -0
- fourier_samples-0.1.0/tests/test_platforms.py +88 -0
- fourier_samples-0.1.0/tests/test_preparers.py +147 -0
- fourier_samples-0.1.0/tests/test_presets.py +41 -0
- fourier_samples-0.1.0/tests/test_progress.py +30 -0
- fourier_samples-0.1.0/tests/test_provider_report.py +38 -0
- fourier_samples-0.1.0/tests/test_providers.py +169 -0
- fourier_samples-0.1.0/tests/test_prune_missing.py +59 -0
- fourier_samples-0.1.0/tests/test_public_commands.py +265 -0
- fourier_samples-0.1.0/tests/test_quiet_build.py +113 -0
- fourier_samples-0.1.0/tests/test_ratings.py +349 -0
- fourier_samples-0.1.0/tests/test_ratings_without_live.py +185 -0
- fourier_samples-0.1.0/tests/test_render.py +273 -0
- fourier_samples-0.1.0/tests/test_render_profile_fields.py +163 -0
- fourier_samples-0.1.0/tests/test_resolve.py +198 -0
- fourier_samples-0.1.0/tests/test_review.py +188 -0
- fourier_samples-0.1.0/tests/test_rows.py +140 -0
- fourier_samples-0.1.0/tests/test_safety.py +249 -0
- fourier_samples-0.1.0/tests/test_scale.py +195 -0
- fourier_samples-0.1.0/tests/test_second_library_cli.py +182 -0
- fourier_samples-0.1.0/tests/test_selection.py +728 -0
- fourier_samples-0.1.0/tests/test_sets.py +320 -0
- fourier_samples-0.1.0/tests/test_settings.py +147 -0
- fourier_samples-0.1.0/tests/test_setup_commands.py +1027 -0
- fourier_samples-0.1.0/tests/test_shadow.py +165 -0
- fourier_samples-0.1.0/tests/test_sononym.py +224 -0
- fourier_samples-0.1.0/tests/test_sound_model.py +571 -0
- fourier_samples-0.1.0/tests/test_sources_apart.py +293 -0
- fourier_samples-0.1.0/tests/test_speed_caches.py +56 -0
- fourier_samples-0.1.0/tests/test_synthetic_golden.py +63 -0
- fourier_samples-0.1.0/tests/test_taxonomy.py +1538 -0
- fourier_samples-0.1.0/tests/test_taxonomy_file.py +62 -0
- fourier_samples-0.1.0/tests/test_timings.py +25 -0
- fourier_samples-0.1.0/tests/test_tunables_inventory.py +53 -0
- fourier_samples-0.1.0/tests/test_validate.py +136 -0
- fourier_samples-0.1.0/tests/test_verify.py +293 -0
- fourier_samples-0.1.0/tests/test_why.py +204 -0
- fourier_samples-0.1.0/uv.lock +2329 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something Fourier Samples did wrong, or a crash
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for the report. Please leave out personal details (names, paths with your user
|
|
9
|
+
name, your library's pack names) and don't attach audio you don't have the rights to
|
|
10
|
+
share. A security problem goes to the private form instead: Security tab, "Report a
|
|
11
|
+
vulnerability".
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happened
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened
|
|
16
|
+
description: The command you ran and what it did. Paste the error or traceback if there was one.
|
|
17
|
+
render: text
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: expected
|
|
22
|
+
attributes:
|
|
23
|
+
label: What you expected
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: reproduce
|
|
28
|
+
attributes:
|
|
29
|
+
label: Steps to reproduce
|
|
30
|
+
description: If it happens with `fourier demo` too, say so; that's the easiest case to reproduce.
|
|
31
|
+
- type: input
|
|
32
|
+
id: version
|
|
33
|
+
attributes:
|
|
34
|
+
label: fourier --version
|
|
35
|
+
placeholder: fourier (Fourier Samples) 0.1.0
|
|
36
|
+
validations:
|
|
37
|
+
required: true
|
|
38
|
+
- type: input
|
|
39
|
+
id: os
|
|
40
|
+
attributes:
|
|
41
|
+
label: OS and version
|
|
42
|
+
placeholder: macOS 15.3 (Apple silicon), Ubuntu 24.04, ...
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
- type: input
|
|
46
|
+
id: python
|
|
47
|
+
attributes:
|
|
48
|
+
label: Python version
|
|
49
|
+
placeholder: "3.12.8"
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
52
|
+
- type: textarea
|
|
53
|
+
id: doctor
|
|
54
|
+
attributes:
|
|
55
|
+
label: fourier doctor output
|
|
56
|
+
description: The output of `fourier doctor` (edit out paths you'd rather not share).
|
|
57
|
+
render: text
|
|
58
|
+
- type: input
|
|
59
|
+
id: device
|
|
60
|
+
attributes:
|
|
61
|
+
label: Device and firmware
|
|
62
|
+
description: If it's about a render or sync.
|
|
63
|
+
placeholder: The device and its OS or firmware version
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: A question, or help getting started
|
|
4
|
+
url: https://github.com/bvk7787/fourier-samples/discussions/categories/q-a
|
|
5
|
+
about: Ask in Discussions (Q&A). Include what you ran and what `fourier doctor` says.
|
|
6
|
+
- name: Share a device profile you made
|
|
7
|
+
url: https://github.com/bvk7787/fourier-samples/discussions/categories/show-and-tell
|
|
8
|
+
about: Profiles from `fourier devices new`, tried on your sampler, before they're cited from its manual.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Device request
|
|
2
|
+
description: Ask for a profile for a sampler Fourier Samples doesn't render for yet
|
|
3
|
+
labels: [device]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
A profile cites the device's manual for every value (docs/device-profiles.md). The
|
|
9
|
+
details below are what a profile needs; if you can draft one yourself, a pull request
|
|
10
|
+
is welcome. Until then, `generic_44k` or `generic_48k` renders a usable library.
|
|
11
|
+
- type: input
|
|
12
|
+
id: device
|
|
13
|
+
attributes:
|
|
14
|
+
label: Device
|
|
15
|
+
placeholder: Maker and model
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: input
|
|
19
|
+
id: manual
|
|
20
|
+
attributes:
|
|
21
|
+
label: Manual
|
|
22
|
+
description: A link to the maker's current manual (PDF), and its firmware or OS version.
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: format
|
|
27
|
+
attributes:
|
|
28
|
+
label: Sample format and limits
|
|
29
|
+
description: |
|
|
30
|
+
What you know, with manual pages if you have them: sample rate and bit depth, mono or
|
|
31
|
+
stereo, file formats, length or slice limits, path or file-name length limits, folder
|
|
32
|
+
depth or files per folder, and storage size.
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
- type: input
|
|
36
|
+
id: load
|
|
37
|
+
attributes:
|
|
38
|
+
label: How samples get onto it
|
|
39
|
+
description: An SD card or USB drive mounted on the computer, a transfer app, copying into a project, or something else.
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
- type: textarea
|
|
43
|
+
id: notes
|
|
44
|
+
attributes:
|
|
45
|
+
label: Anything else
|
|
46
|
+
description: Folder layout the device expects, how its browser sorts, quirks you've hit.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: An idea for Fourier Samples
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What you're trying to do
|
|
9
|
+
description: The problem or the workflow, not only the solution you have in mind.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: What you'd like
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: alternatives
|
|
20
|
+
attributes:
|
|
21
|
+
label: What you've tried or considered
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# GitHub Actions only: the Python dependencies are pinned in uv.lock and updated by hand
|
|
2
|
+
# (the synthetic golden's audio holds only for the locked versions).
|
|
3
|
+
version: 2
|
|
4
|
+
updates:
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: /
|
|
7
|
+
schedule:
|
|
8
|
+
interval: monthly
|
|
9
|
+
groups:
|
|
10
|
+
actions:
|
|
11
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- What and why. Link the issue if there is one. -->
|
|
4
|
+
|
|
5
|
+
## Checks
|
|
6
|
+
|
|
7
|
+
- [ ] Tests run (`pytest -q -n auto tests`), and a behavior change comes with a test
|
|
8
|
+
- [ ] For a curation change: the synthetic golden (`python tests/golden/synthetic_build.py /tmp/syn --check`); if the output is meant to change, regenerated with `--update` and explained above
|
|
9
|
+
- [ ] For a command, option or help-text change: `python tests/test_cli_tree.py --write`
|
|
10
|
+
- [ ] `ruff check src tests`
|
|
11
|
+
- [ ] Docs updated (README, CLAUDE.md, docs/) where the behavior they describe changed
|
|
12
|
+
- [ ] No personal data and no real samples: fixtures use generated audio and invented names (Acme, Northwind, ...), and no real vendor, pack or person is named
|
|
13
|
+
- [ ] For a device profile: every value cites a manual page or is marked a convention, and what I checked on the hardware is described above
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
# Actions minutes are free on a public repository and metered on a private one, where the
|
|
17
|
+
# maintainer runs the same checks locally: every job skips while the repository is private.
|
|
18
|
+
jobs:
|
|
19
|
+
test:
|
|
20
|
+
name: test (${{ matrix.os }}, ${{ matrix.python-version }})
|
|
21
|
+
if: ${{ !github.event.repository.private }}
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
timeout-minutes: 30
|
|
24
|
+
continue-on-error: ${{ matrix.os == 'windows-latest' }} # Windows: best effort for now
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
29
|
+
python-version: ["3.11", "3.12"]
|
|
30
|
+
exclude:
|
|
31
|
+
- os: macos-latest
|
|
32
|
+
python-version: "3.11"
|
|
33
|
+
- os: windows-latest
|
|
34
|
+
python-version: "3.11"
|
|
35
|
+
include:
|
|
36
|
+
- os: ubuntu-latest
|
|
37
|
+
python-version: "3.13"
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
cache: pip
|
|
44
|
+
# the versions in uv.lock: the synthetic golden's audio holds only for these
|
|
45
|
+
# (CLAP and torch left out: the tests use a stand-in)
|
|
46
|
+
- name: Install (locked versions; core + dev)
|
|
47
|
+
shell: bash
|
|
48
|
+
run: |
|
|
49
|
+
python -m pip install --upgrade pip uv
|
|
50
|
+
uv export --frozen --no-hashes --extra dev --no-emit-project > "$RUNNER_TEMP/requirements.lock.txt"
|
|
51
|
+
pip install -r "$RUNNER_TEMP/requirements.lock.txt"
|
|
52
|
+
pip install -e . --no-deps
|
|
53
|
+
- name: Lint
|
|
54
|
+
run: ruff check src tests
|
|
55
|
+
- name: Tests
|
|
56
|
+
run: pytest -q -n auto tests # one worker per CPU (pytest-xdist; conftest.py isolates each)
|
|
57
|
+
- name: Synthetic golden build
|
|
58
|
+
shell: bash
|
|
59
|
+
run: python tests/golden/synthetic_build.py "$RUNNER_TEMP/synthetic" --check
|
|
60
|
+
# the variants below test the pipeline, not the Python version: 3.13 runs the golden only
|
|
61
|
+
- name: Without Sononym, without Live, without both
|
|
62
|
+
if: matrix.python-version != '3.13'
|
|
63
|
+
shell: bash
|
|
64
|
+
run: |
|
|
65
|
+
python tests/golden/synthetic_build.py "$RUNNER_TEMP/no-sononym" --without sononym
|
|
66
|
+
python tests/golden/synthetic_build.py "$RUNNER_TEMP/no-live" --without ableton
|
|
67
|
+
python tests/golden/synthetic_build.py "$RUNNER_TEMP/neither" --without sononym,ableton
|
|
68
|
+
- name: Each preset builds and passes verify
|
|
69
|
+
if: matrix.python-version != '3.13'
|
|
70
|
+
shell: bash
|
|
71
|
+
run: |
|
|
72
|
+
python tests/golden/synthetic_build.py "$RUNNER_TEMP/breaks-acid" --preset breaks-acid
|
|
73
|
+
python tests/golden/synthetic_build.py "$RUNNER_TEMP/balanced" --preset balanced
|
|
74
|
+
- name: A small library's master scales to it
|
|
75
|
+
if: matrix.python-version != '3.13'
|
|
76
|
+
shell: bash
|
|
77
|
+
run: python tests/golden/synthetic_build.py "$RUNNER_TEMP/scaled" --scale --preset balanced
|
|
78
|
+
- name: An interrupted build resumes to the same result
|
|
79
|
+
if: matrix.python-version != '3.13'
|
|
80
|
+
shell: bash
|
|
81
|
+
run: python tests/golden/synthetic_build.py "$RUNNER_TEMP/resume" --check --interrupt KICKS,PADS,VOX
|
|
82
|
+
|
|
83
|
+
package:
|
|
84
|
+
# what `pip install` gives a user: the sdist and wheel build, their metadata passes twine,
|
|
85
|
+
# and the wheel installed with its declared dependencies (no checkout, no [clap]) runs
|
|
86
|
+
name: package (build, install, run)
|
|
87
|
+
if: ${{ !github.event.repository.private }}
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
timeout-minutes: 20
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
- uses: actions/setup-python@v5
|
|
93
|
+
with:
|
|
94
|
+
python-version: "3.12"
|
|
95
|
+
cache: pip
|
|
96
|
+
- name: Build the sdist and wheel
|
|
97
|
+
run: |
|
|
98
|
+
python -m pip install --upgrade pip uv
|
|
99
|
+
uv build
|
|
100
|
+
ls -l dist
|
|
101
|
+
- name: Check the metadata
|
|
102
|
+
run: uvx twine check --strict dist/*
|
|
103
|
+
- name: Check what the wheel holds
|
|
104
|
+
run: |
|
|
105
|
+
python -m zipfile -l dist/*.whl > "$RUNNER_TEMP/wheel.txt"
|
|
106
|
+
for f in fourier/__main__.py fourier/demo.py fourier/_config/tunables.yaml \
|
|
107
|
+
fourier/_config/devices/m8_tracker.yaml licenses/LICENSE licenses/NOTICE; do
|
|
108
|
+
grep -q "$f" "$RUNNER_TEMP/wheel.txt" || { echo "missing from the wheel: $f"; exit 1; }
|
|
109
|
+
done
|
|
110
|
+
- name: Install the wheel into a clean venv
|
|
111
|
+
run: |
|
|
112
|
+
python -m venv "$RUNNER_TEMP/venv"
|
|
113
|
+
"$RUNNER_TEMP/venv/bin/pip" install --upgrade pip
|
|
114
|
+
"$RUNNER_TEMP/venv/bin/pip" install dist/*.whl
|
|
115
|
+
- name: Run the installed command
|
|
116
|
+
working-directory: ${{ runner.temp }} # away from the checkout's src/ and config/
|
|
117
|
+
shell: bash
|
|
118
|
+
run: |
|
|
119
|
+
export PATH="$RUNNER_TEMP/venv/bin:$PATH" FOURIER_HOME="$RUNNER_TEMP/home"
|
|
120
|
+
fourier --version
|
|
121
|
+
python -m fourier --help
|
|
122
|
+
fourier devices list
|
|
123
|
+
# no library and no database here, so doctor reports FAILs and exits non-zero:
|
|
124
|
+
# it only has to run to the end
|
|
125
|
+
fourier doctor > doctor.txt 2>&1 || true
|
|
126
|
+
cat doctor.txt
|
|
127
|
+
if grep -q Traceback doctor.txt; then exit 1; fi
|
|
128
|
+
fourier demo --dir "$RUNNER_TEMP/demo"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# A version tag (v0.1.0) builds the package and publishes it to PyPI with Trusted Publishing:
|
|
4
|
+
# no token is stored anywhere. PyPI trusts this workflow once the project's trusted publisher
|
|
5
|
+
# names it (github.com/bvk7787/fourier-samples, workflow release.yml, environment pypi).
|
|
6
|
+
# The tag must match the version in pyproject.toml. Nothing runs while the repository is private.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
if: ${{ !github.event.repository.private }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 15
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
- name: The tag matches the version
|
|
27
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
28
|
+
shell: bash
|
|
29
|
+
run: |
|
|
30
|
+
want="v$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
|
|
31
|
+
[ "$GITHUB_REF_NAME" = "$want" ] || { echo "tag $GITHUB_REF_NAME, pyproject says $want"; exit 1; }
|
|
32
|
+
- name: Build the sdist and wheel
|
|
33
|
+
run: |
|
|
34
|
+
python -m pip install --upgrade pip build twine
|
|
35
|
+
python -m build
|
|
36
|
+
twine check --strict dist/*
|
|
37
|
+
- name: The wheel installs and runs
|
|
38
|
+
shell: bash
|
|
39
|
+
run: |
|
|
40
|
+
python -m venv "$RUNNER_TEMP/v"
|
|
41
|
+
"$RUNNER_TEMP/v/bin/pip" install dist/*.whl
|
|
42
|
+
"$RUNNER_TEMP/v/bin/fourier" --version
|
|
43
|
+
"$RUNNER_TEMP/v/bin/fourier" demo --dir "$RUNNER_TEMP/demo"
|
|
44
|
+
- uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
publish:
|
|
50
|
+
needs: build
|
|
51
|
+
if: ${{ !github.event.repository.private && startsWith(github.ref, 'refs/tags/') }}
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
timeout-minutes: 10
|
|
54
|
+
environment:
|
|
55
|
+
name: pypi
|
|
56
|
+
url: https://pypi.org/project/fourier-samples/
|
|
57
|
+
permissions:
|
|
58
|
+
id-token: write # Trusted Publishing: PyPI checks this workflow's identity
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/download-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: dist
|
|
63
|
+
path: dist/
|
|
64
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.venv/
|
|
5
|
+
venv/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.python-version
|
|
11
|
+
.DS_Store
|
|
12
|
+
# device manual PDFs kept beside the checkout (makers' copyright; never committed)
|
|
13
|
+
docs/manuals/
|
|
14
|
+
# a local configuration
|
|
15
|
+
fourier.toml
|
|
16
|
+
# local overrides
|
|
17
|
+
/local/
|
|
18
|
+
/CLAUDE.local.md
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Instructions for coding agents
|
|
2
|
+
|
|
3
|
+
Helping someone *use* Fourier Samples (their library, a build, a device)? Read
|
|
4
|
+
[skills/fourier/SKILL.md](skills/fourier/SKILL.md). Changing its code? Read on.
|
|
5
|
+
|
|
6
|
+
- Read [CLAUDE.md](CLAUDE.md) first: the ground rules (the library's files are never changed,
|
|
7
|
+
device facts come from the manuals, no one's library in the code), the architecture, and the
|
|
8
|
+
checks to run before a change is done.
|
|
9
|
+
- Adding or changing a device profile: [docs/device-profiles.md](docs/device-profiles.md).
|
|
10
|
+
- Contributing (tests, the CLI snapshot, what a pull request needs):
|
|
11
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
12
|
+
- Ratings don't need Ableton Live: `fourier review rate` and `fourier review import` write the
|
|
13
|
+
same store Live's tag harvest writes (packs/ratings.py).
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Fourier Samples are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html) (before 1.0, a minor version may
|
|
6
|
+
change the CLI or the config).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-10-04
|
|
9
|
+
|
|
10
|
+
The first public release.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **The command line, for people new to it.** `fourier --help` lists seventeen commands in
|
|
15
|
+
sections (Get started, Build and load, Releases, Look inside, Settings, Listen and rate,
|
|
16
|
+
Advanced). `fourier setup` is a step-by-step wizard (or `--yes` with flags): the sample
|
|
17
|
+
folders (counted, with a warning for cloud-only files), devices and style ("What do you
|
|
18
|
+
make?"), output folders, the config file, the CLAP model (it installs PyTorch and
|
|
19
|
+
Transformers into the running environment with uv or pip, the CPU-only PyTorch on Linux
|
|
20
|
+
without an NVIDIA GPU, and downloads the pinned model), an optional local LLM through Ollama,
|
|
21
|
+
then doctor's checks and the first build. `fourier build` (every category; or one) scans the
|
|
22
|
+
library and analyzes what's new before it builds (`--no-scan` skips both), with stage headers
|
|
23
|
+
and an estimate up front; on a terminal its Build and Verify stages show progress and a
|
|
24
|
+
summary (what it built, what it left empty, verify's result), with everything else in a log
|
|
25
|
+
in `<home>/logs` (`--verbose` prints it all). The steps underneath are `fourier tools` (`scan`, `analyze`,
|
|
26
|
+
`train`, `audit`, `import-folder`, `dedup`, `resolve`, `db-stats`); `publish --dry-run` and
|
|
27
|
+
`render --dry-run` preview what a release or a render would change.
|
|
28
|
+
- **Curation.** `fourier build` turns a sample library into one master of
|
|
29
|
+
`CATEGORY/family/file.wav` folders: nineteen categories in play order (an overlay can add
|
|
30
|
+
more), families clustered from CLAP embeddings and named for what they sound like, drum kits
|
|
31
|
+
(`KITS`) and slice-ready loops (`SLICE`), and a manifest recording where every file came from
|
|
32
|
+
and why it's there. Builds are deterministic and stable (a rule change moves only the files
|
|
33
|
+
it touches), resumable (`--resume`), and swapped into place only when every category built
|
|
34
|
+
and verify passed. A category the library has too few samples for is left empty and named,
|
|
35
|
+
not a failure.
|
|
36
|
+
- **The master's size follows the library** (`scale = "library"`): a style's budgets are for a
|
|
37
|
+
large library, and a smaller one gets a master in proportion. `fourier doctor`, setup and
|
|
38
|
+
`build --dry-run` say how big it will be. `scale = "off"` and `files = N` keep fixed budgets;
|
|
39
|
+
`size` caps them to fit a device.
|
|
40
|
+
- **Export DSP.** DC offset, phase-flipped stereo, clicks at the end, hot starts, long tails,
|
|
41
|
+
per-folder loudness, and notes a few cents off are fixed on the way into the master.
|
|
42
|
+
- **Any library layout, with or without other apps.** A build's scan reads Sononym's analysis
|
|
43
|
+
and Ableton Live's auto-tags when they're there, and otherwise walks the library folders.
|
|
44
|
+
Neither app is needed: built-in `path` and `audio` classifiers (folder and file names, WAV
|
|
45
|
+
chunks, and the audio itself) stand in, with your own words (`words`), and `vendors = "auto"`
|
|
46
|
+
reads each folder as vendor/pack folders, folders by sound type, an umbrella of packs or a
|
|
47
|
+
flat folder. Files no name rule recognizes are placed by sound: by CLAP's prompts, and by a
|
|
48
|
+
sound model trained on your own library (below). Fourier's own analysis (librosa features,
|
|
49
|
+
CLAP embeddings, sample-chain events, loop trims, pYIN roots and keys) runs with or without
|
|
50
|
+
Sononym and is stored apart from Sononym's; a resolver records which source each value a
|
|
51
|
+
build uses came from. The library's own files are never changed.
|
|
52
|
+
- **A sound model trained on your library** (without Sononym). The first build trains a small
|
|
53
|
+
classifier over each sample's CLAP embedding and Fourier's own measurements, taught by how
|
|
54
|
+
your sample makers named their files and folders and by your ratings (never by Sononym's or
|
|
55
|
+
Live's analysis), once the names label enough samples; it retrains when the library has grown
|
|
56
|
+
a lot, and keeps it only when it's reliable on the packs it didn't learn from; `fourier tools
|
|
57
|
+
train` trains it any time. It places what no name rule recognizes when it's confident, and
|
|
58
|
+
its weights and report stay in your Fourier home. Fourier ships no
|
|
59
|
+
weights: they'd be learned from licensed samples. `fourier setup --no-sound-model` turns it
|
|
60
|
+
off.
|
|
61
|
+
- **Cloud-synced libraries.** `fourier setup` and `fourier doctor` count the files a cloud
|
|
62
|
+
drive keeps only online, the analysis skips them (`fourier tools analyze --download` fetches
|
|
63
|
+
them first), and a build downloads the ones it picks before reading any and stops, writing
|
|
64
|
+
nothing, if one won't download.
|
|
65
|
+
- **A second library** can share the Fourier home: another config (`fourier setup --to
|
|
66
|
+
other.toml`) gets its own master, renders and releases.
|
|
67
|
+
- **Checks and explanations.** `fourier verify` checks the master against every curation rule
|
|
68
|
+
(and, with `--render`, scratch device renders); `fourier why` says where a sample landed and
|
|
69
|
+
which rule put it there, or why it was left out, and `why --unrecognized` lists what no rule
|
|
70
|
+
recognized; `fourier diff` compares two builds.
|
|
71
|
+
- **Releases and devices.** `fourier publish` cuts immutable releases; `fourier render` converts
|
|
72
|
+
the master or a release for a device; a released render locks its paths on that device, so
|
|
73
|
+
later releases never move them. `fourier sync` copies a render onto an SD card without
|
|
74
|
+
macOS's `._` files.
|
|
75
|
+
- **Device profiles** for the Elektron Digitakt 2 and the Dirtywave M8, every value citing a
|
|
76
|
+
page of the device's manual or marked as a convention or unverified, plus `generic_44k`,
|
|
77
|
+
`generic_48k`, `generic_folder` and `generic_sd_card`. `fourier devices new` writes a profile
|
|
78
|
+
for your own device; `fourier devices list|show`.
|
|
79
|
+
- **Configuration.** Style presets (`balanced`, the default and the code's own settings,
|
|
80
|
+
`breaks-acid`, which the other genre styles build on, `hiphop-lofi`, `house-techno`,
|
|
81
|
+
`ambient-cinematic`, `trap`), fifteen knobs (`devices`, `categories`, `tempo`,
|
|
82
|
+
`fold`, `scale`, `files`, `size`, `loudness`, `retune`, `stereo`, `names`, `vendors`, `words`,
|
|
83
|
+
`sets`, `sources`), overlays and `--set KEY=VALUE` layer over the code's defaults; `fourier
|
|
84
|
+
config show|explain` prints what resolved and from where. `fourier doctor` checks what a
|
|
85
|
+
build needs, fails on anything that would stop one, and estimates how long it takes.
|
|
86
|
+
- **The listening loop.** Rate the master's files Keep, Drop or Misfiled with `fourier review
|
|
87
|
+
rate` or `review import` (a CSV file), or with tags in Ableton Live's browser; `fourier
|
|
88
|
+
review` scores a build against the ratings and queues the files whose rating teaches the
|
|
89
|
+
most. Every build follows the ratings.
|
|
90
|
+
- **Search.** `fourier search` by words or a reference file (CLAP), or by duration, tempo and
|
|
91
|
+
descriptors.
|
|
92
|
+
- **`fourier demo`**: the whole pipeline on a generated library, in a sandbox folder with its own
|
|
93
|
+
home and config, with no samples, model or download needed.
|
|
94
|
+
- **Safety guards.** Commands that write or delete refuse a library folder, a release, the
|
|
95
|
+
home folder, a volume root and any folder they didn't make: a build stops on a master holding
|
|
96
|
+
files it didn't make and lists them, renders and the demo replace only folders they marked as
|
|
97
|
+
theirs, and `fourier sync --delete` removes only what it copied to that card. A first run's
|
|
98
|
+
usual errors are one line saying what to run, not a traceback.
|
|
99
|
+
- **Preparer plug-ins** (`fourier.preparers` entry points) for open formats soundfile doesn't
|
|
100
|
+
read.
|
|
101
|
+
- **For people new to Terminal**: a step-by-step getting-started page for the Mac
|
|
102
|
+
(`docs/start.md`); setup takes a folder dragged in from Finder, devices and styles by number
|
|
103
|
+
or name, and asks how big a set (starter, standard, full, with load times for Transfer),
|
|
104
|
+
prepared for hardware or as-is, and which kinds of sound to leave out; `fourier open` shows the
|
|
105
|
+
master, a render, the releases or the logs in your file browser; `fourier config edit` opens
|
|
106
|
+
fourier.toml in a text editor (and runs with a config that doesn't load, which is when it's
|
|
107
|
+
needed); a fourier.toml typed with smart quotes still loads, and a mistake in one names its
|
|
108
|
+
line and the usual fix. `fourier config explain <setting>` says what a setting does in plain
|
|
109
|
+
words, with an example.
|
|
110
|
+
- **A report page**: `fourier open report` opens a page in the web browser with every category
|
|
111
|
+
and family, a play button for each file, where it came from, what the build left out and why,
|
|
112
|
+
and Keep / Drop / Misfiled buttons that export a CSV for `fourier review import`.
|
|
113
|
+
- **Plain answers**: `fourier why` answers in one sentence (`--detail` for every rule, vote and
|
|
114
|
+
score); a command that hits something unexpected says so in one line and keeps the details in
|
|
115
|
+
a file for a bug report; commands with nothing built yet say what to run first.
|
|
116
|
+
- **Loading only what's new**: `fourier render <device> --release v2 --new-only` also copies the
|
|
117
|
+
files v2 adds into a folder of their own, for a loader that can't sync (Elektron Transfer).
|
|
118
|
+
- **Documentation**: the README, a guide to what comes after the first build
|
|
119
|
+
(`docs/guide.md`), the reference (`docs/usage.md`), the curation rules (`docs/curation.md`),
|
|
120
|
+
and a skill for coding assistants (`skills/fourier/SKILL.md`) that teaches one to help with
|
|
121
|
+
Fourier safely.
|
|
122
|
+
- `fourier --version`, and `python -m fourier`.
|
|
123
|
+
- Python 3.11 to 3.13 on macOS and Linux; Windows is experimental.
|
|
124
|
+
|
|
125
|
+
[0.1.0]: https://github.com/bvk7787/fourier-samples/releases/tag/v0.1.0
|