sounddiff 0.2.0__tar.gz → 0.2.1__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.
Files changed (58) hide show
  1. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/workflows/ci.yml +6 -0
  2. {sounddiff-0.2.0 → sounddiff-0.2.1}/CHANGELOG.md +12 -0
  3. {sounddiff-0.2.0 → sounddiff-0.2.1}/CLAUDE.md +7 -3
  4. {sounddiff-0.2.0 → sounddiff-0.2.1}/PKG-INFO +1 -1
  5. {sounddiff-0.2.0 → sounddiff-0.2.1}/pyproject.toml +1 -1
  6. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/__init__.py +1 -1
  7. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/formats.py +16 -1
  8. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_formats.py +29 -0
  9. sounddiff-0.2.0/.github/workflows/labeler.yml +0 -17
  10. {sounddiff-0.2.0 → sounddiff-0.2.1}/.coderabbit.yaml +0 -0
  11. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/CODEOWNERS +0 -0
  12. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/FUNDING.yml +0 -0
  13. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  14. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  15. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  16. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/SECURITY.md +0 -0
  18. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/labeler.yml +0 -0
  19. {sounddiff-0.2.0 → sounddiff-0.2.1}/.github/workflows/release.yml +0 -0
  20. {sounddiff-0.2.0 → sounddiff-0.2.1}/.gitignore +0 -0
  21. {sounddiff-0.2.0 → sounddiff-0.2.1}/.pre-commit-config.yaml +0 -0
  22. {sounddiff-0.2.0 → sounddiff-0.2.1}/CODE_OF_CONDUCT.md +0 -0
  23. {sounddiff-0.2.0 → sounddiff-0.2.1}/CONTRIBUTING.md +0 -0
  24. {sounddiff-0.2.0 → sounddiff-0.2.1}/LICENSE +0 -0
  25. {sounddiff-0.2.0 → sounddiff-0.2.1}/README.md +0 -0
  26. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/api.md +0 -0
  27. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/architecture.md +0 -0
  28. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/cli-2.0-design.md +0 -0
  29. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/contributing.md +0 -0
  30. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/index.md +0 -0
  31. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/install.md +0 -0
  32. {sounddiff-0.2.0 → sounddiff-0.2.1}/docs/usage.md +0 -0
  33. {sounddiff-0.2.0 → sounddiff-0.2.1}/examples/basic_comparison.py +0 -0
  34. {sounddiff-0.2.0 → sounddiff-0.2.1}/examples/batch_compare.py +0 -0
  35. {sounddiff-0.2.0 → sounddiff-0.2.1}/examples/ci_regression_test.py +0 -0
  36. {sounddiff-0.2.0 → sounddiff-0.2.1}/scripts/generate_test_audio.py +0 -0
  37. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/__main__.py +0 -0
  38. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/cli.py +0 -0
  39. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/core.py +0 -0
  40. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/detection.py +0 -0
  41. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/loudness.py +0 -0
  42. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/report.py +0 -0
  43. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/spectral.py +0 -0
  44. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/temporal.py +0 -0
  45. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/threshold.py +0 -0
  46. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/types.py +0 -0
  47. {sounddiff-0.2.0 → sounddiff-0.2.1}/src/sounddiff/voice.py +0 -0
  48. {sounddiff-0.2.0 → sounddiff-0.2.1}/templates/report.html.j2 +0 -0
  49. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/__init__.py +0 -0
  50. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/conftest.py +0 -0
  51. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_cli.py +0 -0
  52. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_detection.py +0 -0
  53. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_loudness.py +0 -0
  54. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_report.py +0 -0
  55. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_spectral.py +0 -0
  56. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_temporal.py +0 -0
  57. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_threshold.py +0 -0
  58. {sounddiff-0.2.0 → sounddiff-0.2.1}/tests/test_voice.py +0 -0
@@ -11,6 +11,12 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v4
14
+ with:
15
+ fetch-depth: 0
16
+ - name: Scan for secrets
17
+ uses: trufflesecurity/trufflehog@main
18
+ with:
19
+ extra_args: --only-verified
14
20
  - uses: actions/setup-python@v5
15
21
  with:
16
22
  python-version: "3.13"
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2026-03-27
9
+
10
+ ### Fixed
11
+
12
+ - Compressed files (MP3, AAC, etc.) processed via ffmpeg now display their original format name instead of "WAV" (by @jaimefgdev, #62)
13
+
14
+ ### Changed
15
+
16
+ - CI consolidated to a single check with TruffleHog secrets scanning
17
+
18
+ [0.2.1]: https://github.com/systemblueteam/sounddiff/compare/v0.2.0...v0.2.1
19
+
8
20
  ## [0.2.0] - 2026-03-27
9
21
 
10
22
  ### Added
@@ -47,7 +47,12 @@ src/sounddiff/
47
47
  ## CI & Release
48
48
 
49
49
  - CI: one `ci` job, lint + test on Python 3.13, Ubuntu only.
50
- - Releases are tag-based. `git tag v0.x.0 && git push --tags` triggers build, PyPI publish (trusted publisher), and GitHub Release.
50
+ - Releases are tag-based. Full flow:
51
+ 1. Bump version in BOTH `pyproject.toml` AND `src/sounddiff/__init__.py`
52
+ 2. Update CHANGELOG.md (Keep a Changelog format)
53
+ 3. PR the version bump. Branch protection requires 1 review -- use `gh pr merge --admin` since self-approval is blocked.
54
+ 4. `git tag v0.x.0 && git push --tags` triggers build, PyPI publish, and GitHub Release.
55
+ 5. Edit the auto-generated release: `gh release edit v0.x.0 --repo systemblueteam/sounddiff --notes "..."` -- the CI-generated notes are basic; write proper ones with contributor credits.
51
56
  - PyPI trusted publisher is configured. Never use API tokens for uploads.
52
57
  - CodeRabbit reviews all PRs including `.github/` files.
53
58
 
@@ -66,11 +71,10 @@ src/sounddiff/
66
71
  ## Project
67
72
 
68
73
  - [Issues](https://github.com/systemblueteam/sounddiff/issues) | [Wiki](https://github.com/systemblueteam/sounddiff/wiki)
69
- - Milestones: v0.2.0 (polish), v0.3.0 (integrations)
74
+ - Milestones: v0.3.0 (integrations), v0.4.0 (TBD)
70
75
 
71
76
  ## Gotchas
72
77
 
73
78
  - `pip` doesn't work system-wide on macOS. Use `pipx install sounddiff` for global CLI access, or work inside the venv.
74
79
  - Spectral delta_db clamps energy to -100 dB floor before computing deltas. Without this, noise floor differences produce absurd values (+80 dB).
75
80
  - Rich Console with `record=True` still writes to stdout. Must pass `file=io.StringIO()` to capture without printing.
76
- - `--verbose` flag exists in the CLI but isn't wired to anything yet.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sounddiff
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Structured audio comparison for producers and developers. Think git diff, but for audio.
5
5
  Project-URL: Homepage, https://github.com/systemblueteam/sounddiff
6
6
  Project-URL: Documentation, https://github.com/systemblueteam/sounddiff/tree/main/docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sounddiff"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Structured audio comparison for producers and developers. Think git diff, but for audio."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """sounddiff: structured audio comparison for producers and developers."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.1"
@@ -21,6 +21,15 @@ NATIVE_FORMATS = {".wav", ".flac", ".ogg", ".aiff", ".aif"}
21
21
  # Formats that require ffmpeg
22
22
  FFMPEG_FORMATS = {".mp3", ".aac", ".m4a", ".wma", ".opus"}
23
23
 
24
+ # Mapping for original format display names in metadata
25
+ FORMAT_DISPLAY_NAMES: dict[str, str] = {
26
+ ".mp3": "MP3",
27
+ ".aac": "AAC",
28
+ ".m4a": "AAC",
29
+ ".wma": "WMA",
30
+ ".opus": "Opus",
31
+ }
32
+
24
33
 
25
34
  def _remove_if_exists(path: str) -> None:
26
35
  """Remove a file if it exists, silently ignoring missing files."""
@@ -100,6 +109,12 @@ def load_audio(path: str | Path) -> tuple[np.ndarray, AudioMetadata]:
100
109
  except RuntimeError as e:
101
110
  raise RuntimeError(f"Cannot read audio file: {original_filepath} ({e})") from e
102
111
 
112
+ if original_filepath != read_filepath:
113
+ ext = original_filepath.suffix.lower()
114
+ display_format = FORMAT_DISPLAY_NAMES.get(ext, ext.lstrip(".").upper())
115
+ else:
116
+ display_format = info.format
117
+
103
118
  try:
104
119
  file_size: int | None = original_filepath.stat().st_size
105
120
  except OSError:
@@ -111,7 +126,7 @@ def load_audio(path: str | Path) -> tuple[np.ndarray, AudioMetadata]:
111
126
  sample_rate=sample_rate,
112
127
  channels=data.shape[1],
113
128
  bit_depth=_subtype_to_bits(info.subtype),
114
- format_name=info.format,
129
+ format_name=display_format,
115
130
  frames=len(data),
116
131
  file_size=file_size,
117
132
  )
@@ -56,6 +56,35 @@ class TestLoadAudio:
56
56
  data, meta = load_audio(FIXTURES_DIR / "sine_a.wav")
57
57
  assert meta.frames == len(data)
58
58
 
59
+ def test_transcoded_format_name_is_correct(self, tmp_path: Path) -> None:
60
+ """Verifies that transcoded files show their original format name, not WAV."""
61
+ from unittest.mock import patch
62
+
63
+ # 1. Creamos un archivo MP3 falso para pasar la validación de path.exists()
64
+ fake_mp3 = tmp_path / "test.mp3"
65
+ fake_mp3.write_text("fake audio content")
66
+
67
+ # 2. Simulamos que ffmpeg existe y que la lectura del WAV temporal funciona
68
+ with (
69
+ patch("sounddiff.formats.shutil.which", return_value="ffmpeg"),
70
+ patch("sounddiff.formats.subprocess.run"),
71
+ patch("sounddiff.formats.sf.info") as mock_info,
72
+ patch("sounddiff.formats.sf.read") as mock_read,
73
+ ):
74
+ # Configuramos el mock para simular lo que devolvería el WAV temporal
75
+ class MockInfo:
76
+ format = "WAV"
77
+ subtype = "PCM_16"
78
+
79
+ mock_info.return_value = MockInfo()
80
+ mock_read.return_value = (np.zeros((100, 2), dtype=np.float64), 44100)
81
+
82
+ # 3. Llamamos a tu función
83
+ _, meta = load_audio(fake_mp3)
84
+
85
+ # 4. LA COMPROBACIÓN FINAL: Debe decir MP3 y no WAV
86
+ assert meta.format_name == "MP3"
87
+
59
88
  def test_file_size_is_populated(self) -> None:
60
89
  _, meta = load_audio(FIXTURES_DIR / "sine_a.wav")
61
90
  assert meta.file_size is not None
@@ -1,17 +0,0 @@
1
- name: Labeler
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize]
6
-
7
- permissions:
8
- contents: read
9
- pull-requests: write
10
-
11
- jobs:
12
- label:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/labeler@v5
16
- with:
17
- repo-token: ${{ secrets.GITHUB_TOKEN }}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes