Skip to content

Commit f458971

Browse files
authored
Add libtorchaudio cpp example (#1349)
1 parent fd4ee24 commit f458971

File tree

10 files changed

+168
-0
lines changed

10 files changed

+168
-0
lines changed

examples/libtorchaudio/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build
2+
data/output.wav
3+
data/pipeline.zip
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
3+
project(libtorchaudio-cpp-example)
4+
5+
SET(BUILD_LIBTORCHAUDIO ON CACHE BOOL "Build libtorchaudio")
6+
SET(BUILD_SOX ON CACHE BOOL "Build libsox into libtorchaudio")
7+
8+
SET(BUILD_KALDI OFF CACHE BOOL "Build Kaldi into libtorchaudio")
9+
SET(BUILD_TRANSDUCER OFF CACHE BOOL "Build Python binding")
10+
SET(BUILD_TORCHAUDIO_PYTHON_EXTENSION OFF CACHE BOOL "Build Python binding")
11+
12+
find_package(Torch REQUIRED)
13+
message("libtorchaudio CMakeLists: ${TORCH_CXX_FLAGS}")
14+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
15+
16+
add_subdirectory(../.. libtorchaudio)
17+
18+
add_executable(main main.cpp)
19+
target_link_libraries(main "${TORCH_LIBRARIES}" "${TORCHAUDIO_LIBRARY}")
20+
set_property(TARGET main PROPERTY CXX_STANDARD 14)

examples/libtorchaudio/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Example usage: libtorchaudio
2+
3+
This example demonstrates how you can use torchaudio's I/O features in C++ application, in addition to PyTorch's operations.
4+
5+
To try this example, simply run `./run.sh`. This script will
6+
7+
1. Create an audio preprocessing pipeline with TorchScript and dump it to a file.
8+
2. Build the application using `libtorch` and `libtorchaudio`.
9+
3. Execute the preprocessing pipeline on an example audio.
10+
11+
The detail of the preprocessing pipeline can be found in [`create_jittable_pipeline.py`](./create_jittable_pipeline.py).
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Create a data preprocess pipeline that can be run with libtorchaudio
4+
"""
5+
import os
6+
import argparse
7+
8+
import torch
9+
import torchaudio
10+
11+
12+
class Pipeline(torch.nn.Module):
13+
"""Example audio process pipeline.
14+
15+
This example load waveform from a file then apply effects and save it to a file.
16+
"""
17+
def __init__(self):
18+
super().__init__()
19+
rir, sample_rate = _load_rir()
20+
self.register_buffer('rir', rir)
21+
self.rir_sample_rate: int = sample_rate
22+
23+
def forward(self, input_path: str, output_path: str):
24+
torchaudio.sox_effects.init_sox_effects()
25+
26+
# 1. load audio
27+
waveform, sample_rate = torchaudio.load(input_path)
28+
29+
# 2. Add background noise
30+
alpha = 0.01
31+
waveform = alpha * torch.randn_like(waveform) + (1 - alpha) * waveform
32+
33+
# 3. Reample the RIR filter to much the audio sample rate
34+
rir, _ = torchaudio.sox_effects.apply_effects_tensor(
35+
self.rir, self.rir_sample_rate, effects=[["rate", str(sample_rate)]])
36+
rir = rir / torch.norm(rir, p=2)
37+
rir = torch.flip(rir, [1])
38+
39+
# 4. Apply RIR filter
40+
waveform = torch.nn.functional.pad(waveform, (rir.shape[1] - 1, 0))
41+
waveform = torch.nn.functional.conv1d(waveform[None, ...], rir[None, ...])[0]
42+
43+
# Save
44+
torchaudio.save(output_path, waveform, sample_rate)
45+
46+
47+
def _create_jit_pipeline(output_path):
48+
module = torch.jit.script(Pipeline())
49+
print("*" * 40)
50+
print("* Pipeline code")
51+
print("*" * 40)
52+
print()
53+
print(module.code)
54+
print("*" * 40)
55+
module.save(output_path)
56+
57+
58+
def _get_path(*paths):
59+
return os.path.join(os.path.dirname(__file__), *paths)
60+
61+
62+
def _load_rir():
63+
path = _get_path("data", "rir.wav")
64+
return torchaudio.load(path)
65+
66+
67+
def _parse_args():
68+
parser = argparse.ArgumentParser(description=__doc__)
69+
parser.add_argument(
70+
"--output-path",
71+
default=_get_path("data", "pipeline.zip"),
72+
help="Output JIT file."
73+
)
74+
return parser.parse_args()
75+
76+
77+
def _main():
78+
args = _parse_args()
79+
_create_jit_pipeline(args.output_path)
80+
81+
82+
if __name__ == '__main__':
83+
_main()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The files in this directory are originated from [VOiCES](https://iqtlabs.github.io/voices/) dataset, which is licensed under Creative Commos BY 4.0. They are modified to fit into the tutorial.
2+
3+
* `input.wav`: `VOiCES_devkit/source-16k/train/sp0307/Lab41-SRI-VOiCES-src-sp0307-ch127535-sg0042.wav`
4+
5+
* `rir.wav`: `VOiCES_devkit/distant-16k/room-response/rm1/impulse/Lab41-SRI-VOiCES-rm1-impulse-mc01-stu-clo.wav`
106 KB
Binary file not shown.
9.12 KB
Binary file not shown.

examples/libtorchaudio/main.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <torch/script.h>
2+
3+
int main(int argc, char* argv[]) {
4+
if (argc !=4) {
5+
std::cerr << "Usage: " << argv[0] << " <JIT_OBJECT> <INPUT_FILE> <OUTPUT_FILE>" << std::endl;
6+
return -1;
7+
}
8+
9+
torch::jit::script::Module module;
10+
std::cout << "Loading module from: " << argv[0] << std::endl;
11+
try {
12+
module = torch::jit::load(argv[1]);
13+
} catch (const c10::Error &error) {
14+
std::cerr << "Failed to load the module:" << error.what() << std::endl;
15+
return -1;
16+
}
17+
18+
std::cout << "Performing the process ..." << std::endl;
19+
module.forward({c10::IValue(argv[2]), c10::IValue(argv[3])});
20+
std::cout << "Done." << std::endl;
21+
}

examples/libtorchaudio/run.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
3+
set -eux
4+
5+
this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
6+
7+
build_dir="${this_dir}/build"
8+
data_dir="${this_dir}/data"
9+
jit_file="${data_dir}/pipeline.zip"
10+
input_file="${data_dir}/input.wav"
11+
output_file="${data_dir}/output.wav"
12+
13+
cd "${this_dir}"
14+
python create_jittable_pipeline.py
15+
16+
mkdir -p "${build_dir}"
17+
cd "${build_dir}"
18+
cmake -GNinja \
19+
-DCMAKE_PREFIX_PATH="$(python -c 'import torch;print(torch.utils.cmake_prefix_path)')" \
20+
-DBUILD_SOX=ON \
21+
-DBUILD_KALDI=OFF \
22+
..
23+
cmake --build . --target main
24+
./main "${jit_file}" "${input_file}" "${output_file}"

torchaudio/csrc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ if(BUILD_LIBTORCHAUDIO)
4949

5050
target_link_libraries(
5151
libtorchaudio
52+
${TORCH_LIBRARIES}
5253
${TORCHAUDIO_THIRD_PARTIES}
5354
)
5455

0 commit comments

Comments
 (0)