Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build-installers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ jobs:
<key>CFBundleDisplayName</key>
<string>SoundDocs Capture Agent</string>
<key>CFBundleVersion</key>
<string>0.1.13</string>
<string>0.2.0</string>
<key>CFBundleShortVersionString</key>
<string>0.1.13</string>
<string>0.2.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleIconFile</key>
Expand All @@ -196,7 +196,7 @@ jobs:
EOF

# Build package
pkgbuild --root pkg-root --identifier org.sounddocs.capture-agent --version 0.1.13 --install-location / SoundDocsAgent-macOS.pkg
pkgbuild --root pkg-root --identifier org.sounddocs.capture-agent --version 0.2.0 --install-location / SoundDocsAgent-macOS.pkg

- name: Upload macOS installer
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -244,7 +244,7 @@ jobs:
cd agents/capture-agent-py
cat > installer.nsi << 'EOF'
!define APPNAME "SoundDocs Capture Agent"
!define APPVERSION "0.1.13"
!define APPVERSION "0.2.0"
Name "${APPNAME}"
OutFile "SoundDocsAgent-Windows.exe"
InstallDir "$PROGRAMFILES\SoundDocs"
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.5.6.7] - 2025-09-25

### Added

- **Signal Generator for Capture Agent**: Added comprehensive signal generation capabilities to the capture agent
- Pink Noise Generator: Professional-grade pink noise (1/f spectrum) using Voss-McCartney algorithm
- White Noise Generator: Full-spectrum white noise for system calibration
- Sine Wave Generator: Pure tone generation with adjustable frequency (20Hz - 20kHz)
- Sine Sweep Generator: Logarithmic sweep for system testing and alignment
- Click Track Generator: Metronome/timing reference with adjustable BPM
- Configurable output routing to any available audio channel
- Real-time signal generation with minimal latency
- WebSocket control interface for remote signal control from web UI
- **Internal Loopback Measurement**: Added loopback mode for measuring systems internally
- Routes generated signal directly to reference channel for internal system measurement
- Enables measuring DSP chains, plugins, and software signal paths without physical connections
- Useful for analyzing digital signal processing and software-based audio systems

### Changed

- **Capture Agent Version**: Bumped to `0.2.0` to reflect major feature addition
- **Web App Version**: Updated to `1.5.6.7`

## [1.5.6.6] - 2025-09-21

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ SoundDocs is a modern web application meticulously crafted for audio engineers,

SoundDocs is provided free of charge and is open source under the AGPL v3 license.

**Privacy Promise**: Just because SoundDocs is free with no ads doesn't mean you are the product. We are committed to never selling, sharing, or monetizing your personal data. Your projects, documents, and information remain yours, always.

![SoundDocs Hero Preview](https://i.postimg.cc/bJdc5Hmz/Screenshot-2025-06-05-at-19-21-01.png)

## ✨ Core Features
Expand Down
2 changes: 1 addition & 1 deletion agents/capture-agent-py/capture_agent/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ def blocks(self) -> Generator[np.ndarray, None, None]:
# The `read` method returns a tuple (data, overflowed_boolean)
data, overflowed = self.stream.read(self.config.blockSize)
if overflowed:
print("Warning: Audio buffer overflowed.")
pass # Buffer overflow tracked
yield data
8 changes: 4 additions & 4 deletions agents/capture-agent-py/capture_agent/dsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def log_memory_usage():
process = psutil.Process(os.getpid())
memory_info = process.memory_info()
memory_mb = memory_info.rss / 1024 / 1024
print(f"DSP Memory: {memory_mb:.1f} MB, Work arrays: {len(_work_arrays)}")
except Exception as e:
print(f"Memory monitoring error: {e}")
pass # Memory stats tracked
except Exception:
pass # Memory monitoring error

def clear_dsp_caches():
"""Clear DSP caches to free memory.
Expand Down Expand Up @@ -670,7 +670,7 @@ def compute_metrics(block: np.ndarray, config: CaptureConfig) -> tuple[TFData, S
fs = float(config.sampleRate)

# Delay (linear GCC-PHAT you already implemented)
MAX_DELAY_MS = getattr(config, "maxDelayMs", 500.0)
MAX_DELAY_MS = getattr(config, "maxDelayMs", 2000.0)
delay_ms, _ = _delay_pick_applied(x, y, fs, max_ms=MAX_DELAY_MS)

# Integer align with zero-padding (preserve length) + fractional remainder
Expand Down
23 changes: 21 additions & 2 deletions agents/capture-agent-py/capture_agent/schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydantic import BaseModel, Field
from typing import List, Literal, Union
from typing import List, Literal, Union, Optional

# Shared data structures
class Device(BaseModel):
Expand All @@ -23,13 +23,23 @@ class SPLData(BaseModel):
AvgType = Literal["power", "linear", "exp"]
LpfMode = Literal["lpf", "none"]

class SignalGeneratorConfig(BaseModel):
enabled: bool = False
signalType: Literal["sine", "white", "pink", "brown", "blue", "violet", "sine_sweep"] = "sine"
outputChannels: Optional[List[int]] = None # None means all channels
frequency: float = 1000.0 # Hz (for sine)
startFreq: float = 20.0 # Hz (for sweep)
endFreq: float = 20000.0 # Hz (for sweep)
sweepDuration: float = 1.0 # seconds (for sweep)
amplitude: float = 0.5 # 0.0 to 1.0

class CaptureConfig(BaseModel):
deviceId: str
sampleRate: int
blockSize: int
refChan: int
measChan: int

# FFT & Averaging
nfft: int
avg: AvgType
Expand All @@ -40,6 +50,10 @@ class CaptureConfig(BaseModel):
lpfMode: LpfMode
lpfFreq: float

# Signal Generator & Loopback
useLoopback: bool = False # Use loopback for reference channel
generator: Optional[SignalGeneratorConfig] = None

# Message types from client to agent
class HelloMessage(BaseModel):
type: Literal["hello"]
Expand Down Expand Up @@ -72,6 +86,10 @@ class SetManualDelayMessage(BaseModel):
type: Literal["set_manual_delay"]
delay_ms: float | None = None

class UpdateGeneratorMessage(BaseModel):
type: Literal["update_generator"]
config: SignalGeneratorConfig

# Message types from agent to client
class HelloAckMessage(BaseModel):
type: Literal["hello_ack"]
Expand Down Expand Up @@ -121,6 +139,7 @@ class CalibrationDoneMessage(BaseModel):
GetVersionMessage,
DelayFreezeMessage,
SetManualDelayMessage,
UpdateGeneratorMessage,
]

AgentMessage = Union[
Expand Down
Loading
Loading