文件
mynode/packages/whisper-voice-typing/cpp/utils/findLongestSilence_test.cpp
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

168 行
5.2 KiB
C++

#include "findLongestSilence_test.hpp"
#include "findLongestSilence.hpp"
#include "androidUtil.h"
#include "testing.hpp"
#include <string>
#include <vector>
#include <sstream>
#include <cmath>
#include <random>
static void testTones();
static void testToneWithPause();
static void testSilence();
static void testNoise();
struct GeneratedAudio {
std::vector<float> data;
int sampleRate;
int sampleCount;
};
using AudioGenerator = std::function<const float(float)>;
static GeneratedAudio makeAudio(const AudioGenerator& generator, int sampleRate, float duration);
static void expectNoSilence(const GeneratedAudio& audio, const std::string& testLabel);
static void expectSilenceBetween(const GeneratedAudio& audio, float startTimeSeconds, float stopTimeSeconds, const std::string& testLabel);
void findLongestSilence_test() {
testTones();
testToneWithPause();
testSilence();
testNoise();
}
static void testTones() {
for (int frequency = 440; frequency < 1600; frequency += 300) {
std::stringstream messageBuilder;
messageBuilder << "Should not find silence in tone with frequency " << frequency << " HZ.";
auto audioTone = makeAudio([frequency](float t) {
// Also set the amplitude to 0.2f (to more closely match mic input).
return std::sin(t * static_cast<float>(frequency)) * 0.2f;
}, 15000, 10.0f);
expectNoSilence(audioTone, messageBuilder.str());
}
auto lowFrequencyTone = makeAudio([](float t) {
return std::sin(t * 8) * 0.3f;
}, 15000, 10.0f);
expectSilenceBetween(lowFrequencyTone, 0.0f, 10.0f, "Should find silence in a very low-frequency tone");
}
static void testToneWithPause() {
auto audioToneWithPause = makeAudio([](float t) {
if (t < 5.0f || t > 6.0f) {
return std::sin(t * 880);
} else {
return 0.0f;
}
}, 15000, 11.0f);
expectSilenceBetween(audioToneWithPause, 5.0f, 6.0f, "Should find silence when completely silent in a region");
auto audioToneWithTwoPauses = makeAudio([](float t) {
if (t < 1.0f || (t > 8.0f && t < 10.0f)) {
return 0.0f;
} else {
return std::sin(t * 880);
}
}, 15000, 20.0f);
expectSilenceBetween(audioToneWithPause, 5.0f, 6.0f, "Should find silence when completely silent in a region");
}
static void testSilence() {
auto silence = makeAudio([](float t) {
return 0.0f;
}, 16000, 10.0f);
expectSilenceBetween(silence, 0.0f, 10.0f, "Should find silence in a completely silent signal");
}
static void testNoise() {
std::minstd_rand randomness {2};
std::uniform_real_distribution noiseGenerator {-1.0, 1.0};
auto quietNoise = makeAudio([&](float t) {
return noiseGenerator(randomness) * 0.02f;
}, 16000, 5.0f);
expectSilenceBetween(quietNoise, 0.0f, 5.0f, "Should find silence in a tone with low-amplitude noise");
}
static GeneratedAudio makeAudio(const AudioGenerator& generator, int sampleRate, float duration) {
std::vector<float> result { };
int numSamples = static_cast<int>(static_cast<float>(sampleRate) * duration);
for (int i = 0; i < numSamples; i++) {
float time = static_cast<float>(i) / static_cast<float>(sampleRate);
result.push_back(generator(time));
}
return {
.data=result,
.sampleRate=sampleRate,
.sampleCount=numSamples,
};
}
static float samplesToSeconds(int samples, int sampleRate) {
return static_cast<float>(samples) / static_cast<float>(sampleRate);
}
static void expectNoSilence(const GeneratedAudio& audio, const std::string& testLabel) {
auto silence = findLongestSilence(
audio.data,
LongestSilenceOptions {
.sampleRate = audio.sampleRate,
.minSilenceLengthSeconds = 0.02f,
.maximumSilenceStartSamples = audio.sampleCount,
.returnFirstMatch = false,
}
);
if (silence.isValid) {
std::stringstream errorBuilder;
float startSeconds = samplesToSeconds(silence.start, audio.sampleRate);
float stopSeconds = samplesToSeconds(silence.end, audio.sampleRate);
errorBuilder << "Error: Found silence between " << startSeconds << "s and " << stopSeconds << "s";
errorBuilder << ": " << testLabel;
fail(errorBuilder.str());
}
logTestPass(testLabel);
}
static void expectSilenceBetween(const GeneratedAudio& audio, float startTimeSeconds, float stopTimeSeconds, const std::string& testLabel) {
auto silenceResult = findLongestSilence(
audio.data,
LongestSilenceOptions {
.sampleRate = audio.sampleRate,
.minSilenceLengthSeconds = 0.02f,
.maximumSilenceStartSamples = audio.sampleCount,
.returnFirstMatch = false,
}
);
if (!silenceResult.isValid) {
fail("Error: No silence found: " + testLabel);
}
auto checkEndpoint = [&] (int actualValueSamples, float expectedValueSeconds, const std::string& description) {
float actualValueSeconds = samplesToSeconds(actualValueSamples, audio.sampleRate);
float tolerance = 0.1f; // 100ms
if (std::abs(expectedValueSeconds - actualValueSeconds) > tolerance) {
std::stringstream messageBuilder;
messageBuilder << "Error: Silence " << description << " mismatch: ";
messageBuilder << "got " << actualValueSeconds << "s expected " << expectedValueSeconds << "s. ";
messageBuilder << testLabel;
fail(messageBuilder.str());
}
};
checkEndpoint(silenceResult.start, startTimeSeconds, "start time");
checkEndpoint(silenceResult.end, stopTimeSeconds, "stop time");
logTestPass(testLabel);
}