Skip to content

Add mod_soundtouch: pitch-preserving tempo control for file playback#1

Merged
pinc444 merged 2 commits intomasterfrom
copilot/add-soundtouch-module
Feb 20, 2026
Merged

Add mod_soundtouch: pitch-preserving tempo control for file playback#1
pinc444 merged 2 commits intomasterfrom
copilot/add-soundtouch-module

Conversation

Copy link
Copy Markdown

Copilot AI commented Feb 20, 2026

FreeSWITCH's existing speed:+N playback uses sample skipping, which shifts pitch (chipmunk effect). This integrates the SoundTouch library to provide TDHS-based tempo change without pitch shift.

Core changes

  • src/include/switch_ivr.h — Declares switch_ivr_soundtouch_process global function pointer (SWITCH_DECLARE_DATA extern) so the dynamically-loaded module can register itself with the core
  • src/switch_ivr_play_say.c — Defines and initializes the pointer to NULL; in the speed processing block, checks use_soundtouch channel variable and dispatches to SoundTouch if the module is loaded, otherwise falls through to the original sample-skip path (fully backward compatible)

New module: src/mod/applications/mod_soundtouch/

  • mod_soundtouch.cpp — C++ module following mod_cv patterns (SWITCH_BEGIN_EXTERN_C for module entry points). Manages per-session SoundTouch instances via switch_channel_set_private, cleaned up on hangup via a channel state handler. Sets/clears switch_ivr_soundtouch_process on load/unload.
  • Makefile.am — Conditional build guarded by HAVE_SOUNDTOUCH (requires libsoundtouch-dev)

Configuration

  • configure.acPKG_CHECK_MODULES([SOUNDTOUCH], [soundtouch >= 1.7.1])
  • conf/vanilla/autoload_configs/soundtouch.conf.xml — Parsed on load; controls default-enabled, min-tempo, max-tempo

API commands

soundtouch enable <uuid>         # sets use_soundtouch=true
soundtouch disable <uuid>        # clears state and disables
soundtouch tempo <uuid> <0.5–2.0>

Dialplan usage

<action application="set" data="use_soundtouch=true"/>
<action application="playback" data="speed:+1:/path/to/file.wav"/>

Speed values map to SoundTouch tempo: tempo = 1.0 + (0.25 × speed), so speed:+1 → 1.25×, speed:+2 → 1.50×, matching the existing factor used by the sample-skip path.

Original prompt

Problem

FreeSWITCH's current speed control uses simple sample skipping, which causes pitch shift (chipmunk effect). When playing audio files faster using speed:+1, voices become high-pitched and squeaky.

Solution

Integrate SoundTouch library to provide pitch-preserving time-stretching for audio playback.

Implementation Requirements

1. Create new module: src/mod/applications/mod_soundtouch/

Create the following files:

File: src/mod/applications/mod_soundtouch/mod_soundtouch.c

  • Implement SoundTouch wrapper for FreeSWITCH
  • Add tempo control without pitch shift
  • Hook into file playback system
  • Provide API to enable/disable per session
  • Add channel variable use_soundtouch to control usage
  • Support tempo range 0.5x to 2.0x
  • Handle proper cleanup on session end

File: src/mod/applications/mod_soundtouch/Makefile.am

  • Standard FreeSWITCH module build configuration
  • Link against libSoundTouch
  • Include proper headers

2. Integration Points

Add support for calling SoundTouch from the core playback functions:

  • Check for use_soundtouch channel variable
  • If enabled, use SoundTouch for tempo changes
  • Fall back to old method if disabled or not available
  • Maintain backward compatibility

3. Configuration

File: conf/autoload_configs/soundtouch.conf.xml

<configuration name="soundtouch.conf" description="SoundTouch Time-Stretching">
  <settings>
    <param name="default-enabled" value="true"/>
    <param name="min-tempo" value="0.5"/>
    <param name="max-tempo" value="2.0"/>
  </settings>
</configuration>

4. Dependencies

  • libsoundtouch-dev (system package)
  • Document installation: apt-get install libsoundtouch-dev or brew install sound-touch

5. API Commands

Add fs_cli commands:

  • soundtouch enable <uuid> - Enable for session
  • soundtouch disable <uuid> - Disable for session
  • soundtouch tempo <uuid> <value> - Set tempo

6. Usage Examples

Dialplan:

<action application="set" data="use_soundtouch=true"/>
<action application="playback" data="speed:+1:/path/to/file.wav"/>

JavaScript:

session.setVariable("use_soundtouch", "true");
session.streamFile("/path/to/file.wav", function(digits) {
    if (digits == "1") return "speed:+1";  // Natural voice, no chipmunk!
});

7. Testing

  • Verify no chipmunk effect with speed:+1
  • Test tempo range 0.5x to 2.0x
  • Ensure backward compatibility when disabled
  • Test with various audio formats (wav, mp3)
  • Test with different sample rates (8kHz, 16kHz, 48kHz)

Technical Notes

  • Use C++ for SoundTouch integration (it's a C++ library)
  • Ensure thread-safe buffer handling
  • Process audio in real-time chunks
  • Maintain low latency for telephony use
  • Handle stereo and mono audio

Success Criteria

✅ Voice playback at 1.5x speed sounds natural (same pitch)
✅ Module loads without errors
✅ Backward compatible (old behavior when disabled)
✅ Works with existing dialplan speed: syntax
✅ Minimal CPU overhead
✅ Clean unload/reload

Additional Context

This addresses the limitation where speed:+1 in JavaScript callbacks currently causes high-pitched audio. Users want faster playback without pitch shift, similar to how modern media players handle speed changes.

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: pinc444 <148037078+pinc444@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate SoundTouch for pitch-preserving speed control Add mod_soundtouch: pitch-preserving tempo control for file playback Feb 20, 2026
Copilot AI requested a review from pinc444 February 20, 2026 04:10
@pinc444 pinc444 marked this pull request as ready for review February 20, 2026 04:54
@pinc444 pinc444 merged commit 0124c2f into master Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants