music-segment-detector 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # Music Segment Detector
2
+
3
+ Audio music segment detection library - Automatically detect music segments from WAV audio files.
4
+
5
+ English | [中文](./README_ZH.md)
6
+
7
+ ## Features
8
+
9
+ - Multi-feature analysis (RMS, energy, MFCC, spectral centroid, etc.)
10
+ - Automatic detection of music segment start and end times
11
+ - Customizable detection parameters
12
+ - No external dependencies (no ffmpeg required)
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install music-segment-detector
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { analyzeAudio, detectMusicSegments } from "music-segment-detector";
24
+
25
+ // 1. Analyze WAV audio file (with progress callback)
26
+ const features = await analyzeAudio("audio.wav", 2048, 512, (progress) => {
27
+ console.log(`Analysis progress: ${(progress * 100).toFixed(1)}%`);
28
+ });
29
+
30
+ // 2. Detect music segments
31
+ const segments = detectMusicSegments(features, {
32
+ energyPercentile: 50, // Energy percentile threshold (0-100)
33
+ minSegmentDuration: 25, // Minimum segment duration in seconds
34
+ maxGapDuration: 15, // Maximum gap duration in seconds
35
+ smoothWindowSize: 4, // Smoothing window size in seconds
36
+ });
37
+
38
+ // 3. Use detected segments
39
+ segments.forEach((segment) => {
40
+ console.log(`Segment: ${segment.startTime}s - ${segment.endTime}s`);
41
+ console.log(`Duration: ${segment.duration}s`);
42
+ console.log(`Confidence: ${segment.confidence}`);
43
+ });
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### `analyzeAudio(audioPath, windowSize?, hopSize?, onProgress?)`
49
+
50
+ Analyze a WAV audio file and extract features.
51
+
52
+ - `audioPath`: Path to WAV file
53
+ - `windowSize`: Analysis window size (default: 2048)
54
+ - `hopSize`: Window hop size (default: 512)
55
+ - `onProgress`: Optional progress callback function `(progress: number) => void`, parameter is progress value between 0-1
56
+ - Returns: `Promise<AudioFeatures[]>`
57
+
58
+ ### `detectMusicSegments(features, config?)`
59
+
60
+ Detect music segments from audio features.
61
+
62
+ - `features`: Array of audio features
63
+ - `config`: Detection configuration (optional)
64
+ - `energyPercentile`: Energy percentile threshold (0-100, default: 50)
65
+ - `minSegmentDuration`: Minimum segment duration in seconds (default: 25)
66
+ - `maxGapDuration`: Maximum gap duration in seconds (default: 15)
67
+ - `smoothWindowSize`: Smoothing window size in seconds (default: 4)
68
+ - Returns: `MusicSegment[]`
69
+
70
+ ### `saveSegmentsToJson(segments, outputPath, mediaFileName)`
71
+
72
+ Save detection results to JSON format.
73
+
74
+ - `segments`: Array of music segments
75
+ - `outputPath`: Output file path
76
+ - `mediaFileName`: Media file name
77
+ - Returns: `Promise<void>`
78
+
79
+ ### `getFeatureStats(features)`
80
+
81
+ Get statistical information of audio features (for debugging and analysis).
82
+
83
+ - `features`: Array of audio features
84
+ - Returns: Statistics object containing min, max, mean, median for each feature
85
+
86
+ ## Type Definitions
87
+
88
+ ```typescript
89
+ interface AudioFeatures {
90
+ timestamp: number;
91
+ rms: number;
92
+ energy: number;
93
+ zcr: number;
94
+ spectralEnergy: number;
95
+ variance: number;
96
+ mfcc: number[];
97
+ spectralCentroid: number;
98
+ spectralRolloff: number;
99
+ spectralFlatness: number;
100
+ }
101
+
102
+ interface MusicSegment {
103
+ startTime: number;
104
+ endTime: number;
105
+ duration: number;
106
+ confidence: number;
107
+ name?: string;
108
+ }
109
+
110
+ interface DetectionConfig {
111
+ energyPercentile?: number;
112
+ minSegmentDuration?: number;
113
+ maxGapDuration?: number;
114
+ smoothWindowSize?: number;
115
+ }
116
+ ```
117
+
118
+ ## How It Works
119
+
120
+ 1. **Feature Extraction**: Analyze audio using sliding windows to extract multi-dimensional features (energy, MFCC, spectral features, etc.)
121
+ 2. **Multi-Feature Scoring**: Score each time window based on 7 features:
122
+ - Energy intensity
123
+ - Energy stability
124
+ - Spectral centroid (timbre brightness)
125
+ - Spectral flatness (tone vs noise)
126
+ - MFCC continuity (timbre consistency)
127
+ - Zero-crossing rate
128
+ - Spectral rolloff
129
+ 3. **Post-processing**: Smoothing, merging adjacent segments, filtering short segments
130
+
131
+ ## Notes
132
+
133
+ - Only supports WAV format audio files
134
+ - For other formats, use tools like ffmpeg to convert to WAV first
135
+ - Detection accuracy depends on audio quality and configuration parameters
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,80 @@
1
+ export interface AudioFeatures {
2
+ timestamp: number;
3
+ rms: number;
4
+ energy: number;
5
+ zcr: number;
6
+ spectralEnergy: number;
7
+ variance: number;
8
+ mfcc: number[];
9
+ spectralCentroid: number;
10
+ spectralRolloff: number;
11
+ spectralFlatness: number;
12
+ }
13
+ /**
14
+ * 计算音频特征
15
+ * @param audioPath WAV 音频文件路径
16
+ * @param windowSize 分析窗口大小(样本数)
17
+ * @param hopSize 窗口跳跃大小(样本数)
18
+ * @param onProgress 进度回调函数,参数为 0-1 之间的进度值
19
+ */
20
+ export declare function analyzeAudio(audioPath: string, windowSize?: number, hopSize?: number, onProgress?: (progress: number) => void): Promise<AudioFeatures[]>;
21
+ /**
22
+ * 计算特征的统计信息(用于调试和阈值设定)
23
+ */
24
+ export declare function getFeatureStats(features: AudioFeatures[]): {
25
+ rms: {
26
+ min: number;
27
+ max: number;
28
+ mean: number;
29
+ median: number;
30
+ };
31
+ energy: {
32
+ min: number;
33
+ max: number;
34
+ mean: number;
35
+ median: number;
36
+ };
37
+ zcr: {
38
+ min: number;
39
+ max: number;
40
+ mean: number;
41
+ median: number;
42
+ };
43
+ spectralEnergy: {
44
+ min: number;
45
+ max: number;
46
+ mean: number;
47
+ median: number;
48
+ };
49
+ variance: {
50
+ min: number;
51
+ max: number;
52
+ mean: number;
53
+ median: number;
54
+ };
55
+ spectralCentroid: {
56
+ min: number;
57
+ max: number;
58
+ mean: number;
59
+ median: number;
60
+ };
61
+ spectralRolloff: {
62
+ min: number;
63
+ max: number;
64
+ mean: number;
65
+ median: number;
66
+ };
67
+ spectralFlatness: {
68
+ min: number;
69
+ max: number;
70
+ mean: number;
71
+ median: number;
72
+ };
73
+ mfcc: Array<{
74
+ min: number;
75
+ max: number;
76
+ mean: number;
77
+ median: number;
78
+ }>;
79
+ };
80
+ //# sourceMappingURL=audioAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioAnalyzer.d.ts","sourceRoot":"","sources":["../src/audioAnalyzer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAsED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAAa,EACzB,OAAO,GAAE,MAAY,EACrB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GACtC,OAAO,CAAC,aAAa,EAAE,CAAC,CAgE1B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAUzC,KAAK,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;EA+FL"}
@@ -0,0 +1,217 @@
1
+ import fs from "fs/promises";
2
+ import * as WavDecoder from "wav-decoder";
3
+ import Meyda from "meyda";
4
+ /**
5
+ * 从 WAV 文件读取音频数据
6
+ */
7
+ async function readWavFile(filePath) {
8
+ const buffer = await fs.readFile(filePath);
9
+ const audioData = await WavDecoder.decode(buffer.buffer);
10
+ // 如果是多声道,只取第一个声道
11
+ const channelData = audioData.channelData[0];
12
+ const sampleRate = audioData.sampleRate;
13
+ return { sampleRate, channelData };
14
+ }
15
+ /**
16
+ * 计算 RMS(均方根)
17
+ */
18
+ function calculateRMS(samples) {
19
+ let sum = 0;
20
+ for (let i = 0; i < samples.length; i++) {
21
+ sum += samples[i] * samples[i];
22
+ }
23
+ return Math.sqrt(sum / samples.length);
24
+ }
25
+ /**
26
+ * 计算过零率
27
+ */
28
+ function calculateZCR(samples) {
29
+ let count = 0;
30
+ for (let i = 1; i < samples.length; i++) {
31
+ if ((samples[i] >= 0 && samples[i - 1] < 0) ||
32
+ (samples[i] < 0 && samples[i - 1] >= 0)) {
33
+ count++;
34
+ }
35
+ }
36
+ return count / samples.length;
37
+ }
38
+ /**
39
+ * 简单的 FFT 能量分布计算(高频能量)
40
+ */
41
+ function calculateSpectralEnergy(samples) {
42
+ // 简化版:计算高频分量(通过差分近似)
43
+ let highFreqEnergy = 0;
44
+ for (let i = 1; i < samples.length; i++) {
45
+ const diff = samples[i] - samples[i - 1];
46
+ highFreqEnergy += diff * diff;
47
+ }
48
+ return highFreqEnergy / samples.length;
49
+ }
50
+ /**
51
+ * 计算方差
52
+ */
53
+ function calculateVariance(samples, mean) {
54
+ let sum = 0;
55
+ for (let i = 0; i < samples.length; i++) {
56
+ const diff = samples[i] - mean;
57
+ sum += diff * diff;
58
+ }
59
+ return sum / samples.length;
60
+ }
61
+ /**
62
+ * 计算音频特征
63
+ * @param audioPath WAV 音频文件路径
64
+ * @param windowSize 分析窗口大小(样本数)
65
+ * @param hopSize 窗口跳跃大小(样本数)
66
+ * @param onProgress 进度回调函数,参数为 0-1 之间的进度值
67
+ */
68
+ export async function analyzeAudio(audioPath, windowSize = 2048, hopSize = 512, onProgress) {
69
+ const { sampleRate, channelData } = await readWavFile(audioPath);
70
+ const features = [];
71
+ // 滑动窗口分析
72
+ const totalWindows = Math.floor((channelData.length - windowSize) / hopSize);
73
+ for (let i = 0; i < totalWindows; i++) {
74
+ const start = i * hopSize;
75
+ const end = start + windowSize;
76
+ const window = channelData.slice(start, end);
77
+ const timestamp = start / sampleRate;
78
+ // 时域特征
79
+ const rms = calculateRMS(window);
80
+ const energy = rms * rms;
81
+ const zcr = calculateZCR(window);
82
+ const spectralEnergy = calculateSpectralEnergy(window);
83
+ // 计算方差
84
+ let mean = 0;
85
+ for (let j = 0; j < window.length; j++) {
86
+ mean += Math.abs(window[j]);
87
+ }
88
+ mean /= window.length;
89
+ const variance = calculateVariance(window, mean);
90
+ // 使用 Meyda 一次性提取多个特征(更高效)
91
+ const meydaFeatures = Meyda.extract(["mfcc", "spectralCentroid", "spectralRolloff", "spectralFlatness"], window);
92
+ const mfcc = meydaFeatures?.mfcc || new Array(13).fill(0);
93
+ const spectralCentroid = meydaFeatures?.spectralCentroid || 0;
94
+ const spectralRolloff = meydaFeatures?.spectralRolloff || 0;
95
+ const spectralFlatness = meydaFeatures?.spectralFlatness || 0;
96
+ features.push({
97
+ timestamp,
98
+ rms,
99
+ energy,
100
+ zcr,
101
+ spectralEnergy,
102
+ variance,
103
+ mfcc,
104
+ spectralCentroid,
105
+ spectralRolloff,
106
+ spectralFlatness,
107
+ });
108
+ // 调用进度回调
109
+ if (onProgress && i % 100 === 0) {
110
+ onProgress((i + 1) / totalWindows);
111
+ }
112
+ }
113
+ // 确保最后报告 100% 进度
114
+ if (onProgress) {
115
+ onProgress(1);
116
+ }
117
+ return features;
118
+ }
119
+ /**
120
+ * 计算特征的统计信息(用于调试和阈值设定)
121
+ */
122
+ export function getFeatureStats(features) {
123
+ const stats = {
124
+ rms: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
125
+ energy: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
126
+ zcr: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
127
+ spectralEnergy: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
128
+ variance: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
129
+ spectralCentroid: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
130
+ spectralRolloff: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
131
+ spectralFlatness: { min: Infinity, max: -Infinity, mean: 0, median: 0 },
132
+ mfcc: [],
133
+ };
134
+ // 收集所有值用于计算中位数
135
+ const values = {
136
+ rms: [],
137
+ energy: [],
138
+ zcr: [],
139
+ spectralEnergy: [],
140
+ variance: [],
141
+ spectralCentroid: [],
142
+ spectralRolloff: [],
143
+ spectralFlatness: [],
144
+ };
145
+ // 初始化MFCC统计
146
+ const numMfcc = features[0]?.mfcc?.length || 13;
147
+ for (let i = 0; i < numMfcc; i++) {
148
+ stats.mfcc.push({ min: Infinity, max: -Infinity, mean: 0, median: 0 });
149
+ values[`mfcc${i}`] = [];
150
+ }
151
+ features.forEach((f) => {
152
+ // 处理标量特征
153
+ const scalarKeys = [
154
+ "rms",
155
+ "energy",
156
+ "zcr",
157
+ "spectralEnergy",
158
+ "variance",
159
+ "spectralCentroid",
160
+ "spectralRolloff",
161
+ "spectralFlatness",
162
+ ];
163
+ for (const key of scalarKeys) {
164
+ const value = f[key];
165
+ if (!isNaN(value) && isFinite(value)) {
166
+ stats[key].min = Math.min(stats[key].min, value);
167
+ stats[key].max = Math.max(stats[key].max, value);
168
+ stats[key].mean += value;
169
+ values[key].push(value);
170
+ }
171
+ }
172
+ // 处理MFCC特征
173
+ if (f.mfcc) {
174
+ f.mfcc.forEach((value, i) => {
175
+ if (!isNaN(value) && isFinite(value)) {
176
+ stats.mfcc[i].min = Math.min(stats.mfcc[i].min, value);
177
+ stats.mfcc[i].max = Math.max(stats.mfcc[i].max, value);
178
+ stats.mfcc[i].mean += value;
179
+ values[`mfcc${i}`].push(value);
180
+ }
181
+ });
182
+ }
183
+ });
184
+ // 计算均值和中位数
185
+ const scalarKeys = [
186
+ "rms",
187
+ "energy",
188
+ "zcr",
189
+ "spectralEnergy",
190
+ "variance",
191
+ "spectralCentroid",
192
+ "spectralRolloff",
193
+ "spectralFlatness",
194
+ ];
195
+ for (const key of scalarKeys) {
196
+ stats[key].mean /= features.length;
197
+ // 计算中位数
198
+ const sorted = values[key].sort((a, b) => a - b);
199
+ const mid = Math.floor(sorted.length / 2);
200
+ stats[key].median =
201
+ sorted.length % 2 === 0
202
+ ? (sorted[mid - 1] + sorted[mid]) / 2
203
+ : sorted[mid];
204
+ }
205
+ // 计算MFCC的均值和中位数
206
+ for (let i = 0; i < stats.mfcc.length; i++) {
207
+ stats.mfcc[i].mean /= features.length;
208
+ const sorted = values[`mfcc${i}`].sort((a, b) => a - b);
209
+ const mid = Math.floor(sorted.length / 2);
210
+ stats.mfcc[i].median =
211
+ sorted.length % 2 === 0
212
+ ? (sorted[mid - 1] + sorted[mid]) / 2
213
+ : sorted[mid];
214
+ }
215
+ return stats;
216
+ }
217
+ //# sourceMappingURL=audioAnalyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioAnalyzer.js","sourceRoot":"","sources":["../src/audioAnalyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { analyzeAudio, AudioFeatures, getFeatureStats, } from "./audioAnalyzer.js";
2
+ export { detectMusicSegments, MusicSegment, DetectionConfig, } from "./segmentDetector.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // 导出所有公共 API
2
+ export { analyzeAudio, getFeatureStats, } from "./audioAnalyzer.js";
3
+ export { detectMusicSegments, } from "./segmentDetector.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EACL,YAAY,EAEZ,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { AudioFeatures } from "./audioAnalyzer.js";
2
+ export interface MusicSegment {
3
+ startTime: number;
4
+ endTime: number;
5
+ duration: number;
6
+ confidence: number;
7
+ name?: string;
8
+ }
9
+ export interface DetectionConfig {
10
+ energyPercentile?: number;
11
+ minSegmentDuration?: number;
12
+ maxGapDuration?: number;
13
+ smoothWindowSize?: number;
14
+ }
15
+ /**
16
+ * 检测音乐片段 - 使用多特征综合判断(包括MFCC)
17
+ */
18
+ export declare function detectMusicSegments(features: AudioFeatures[], config?: DetectionConfig): MusicSegment[];
19
+ //# sourceMappingURL=segmentDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmentDetector.d.ts","sourceRoot":"","sources":["../src/segmentDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAmB,MAAM,oBAAoB,CAAC;AAEpE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAE9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAgCD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,GAAE,eAAoB,GAC3B,YAAY,EAAE,CAkMhB"}
@@ -0,0 +1,190 @@
1
+ import { getFeatureStats } from "./audioAnalyzer.js";
2
+ const DEFAULT_CONFIG = {
3
+ energyPercentile: 50, // 能量超过中位数
4
+ minSegmentDuration: 25, // 提高到15秒,过滤更多短片段
5
+ maxGapDuration: 15, // 提高到10秒,合并更多相邻片段
6
+ smoothWindowSize: 4, // 提高到3秒,增强平滑效果
7
+ };
8
+ /**
9
+ * 对布尔序列进行平滑处理
10
+ */
11
+ function smoothBooleanSequence(sequence, windowSize) {
12
+ const result = [];
13
+ const halfWindow = Math.floor(windowSize / 2);
14
+ for (let i = 0; i < sequence.length; i++) {
15
+ const start = Math.max(0, i - halfWindow);
16
+ const end = Math.min(sequence.length, i + halfWindow + 1);
17
+ const window = sequence.slice(start, end);
18
+ // 如果窗口内大部分为 true,则判定为音乐
19
+ const trueCount = window.filter((v) => v).length;
20
+ result.push(trueCount > window.length / 2);
21
+ }
22
+ return result;
23
+ }
24
+ /**
25
+ * 检测音乐片段 - 使用多特征综合判断(包括MFCC)
26
+ */
27
+ export function detectMusicSegments(features, config = {}) {
28
+ const cfg = { ...DEFAULT_CONFIG, ...config };
29
+ // 计算特征统计信息
30
+ const stats = getFeatureStats(features);
31
+ // 使用百分位数计算阈值
32
+ const energyValues = features.map((f) => f.energy).sort((a, b) => a - b);
33
+ const energyThreshold = energyValues[Math.floor((energyValues.length * cfg.energyPercentile) / 100)];
34
+ // 计算MFCC相似度阈值(用于检测音乐的连续性)
35
+ const mfccVariances = features.map((f, idx) => {
36
+ if (idx === 0)
37
+ return 0;
38
+ let variance = 0;
39
+ for (let i = 0; i < f.mfcc.length && i < features[idx - 1].mfcc.length; i++) {
40
+ const diff = f.mfcc[i] - features[idx - 1].mfcc[i];
41
+ variance += diff * diff;
42
+ }
43
+ return Math.sqrt(variance);
44
+ });
45
+ const avgMfccVariance = mfccVariances.reduce((a, b) => a + b, 0) / mfccVariances.length;
46
+ // 第一步:基于多特征判断每个时间窗口是否可能是音乐
47
+ const isMusicWindow = features.map((f, idx) => {
48
+ let musicScore = 0;
49
+ let totalWeight = 0;
50
+ // 1. 能量判断(权重:2.0)
51
+ const hasHighEnergy = f.energy > energyThreshold;
52
+ if (hasHighEnergy) {
53
+ musicScore += 2.0;
54
+ }
55
+ totalWeight += 2.0;
56
+ // 2. 能量稳定性判断(权重:1.5)
57
+ if (idx > 0 && idx < features.length - 1) {
58
+ const prevEnergy = features[idx - 1].energy;
59
+ const nextEnergy = features[idx + 1].energy;
60
+ const avgEnergy = (prevEnergy + f.energy + nextEnergy) / 3;
61
+ if (avgEnergy > 0) {
62
+ const variation = Math.abs(f.energy - avgEnergy) / avgEnergy;
63
+ const stabilityScore = 1 - Math.min(variation, 1);
64
+ // 音乐通常更稳定(stabilityScore > 0.3)
65
+ if (stabilityScore > 0.3) {
66
+ musicScore += 1.5 * stabilityScore;
67
+ }
68
+ }
69
+ }
70
+ totalWeight += 1.5;
71
+ // 3. 频谱质心判断(权重:1.0)
72
+ // 音乐通常有更丰富的频率成分,质心在中高频
73
+ const centroidScore = f.spectralCentroid > stats.spectralCentroid.mean * 0.7 &&
74
+ f.spectralCentroid < stats.spectralCentroid.mean * 1.3;
75
+ if (centroidScore) {
76
+ musicScore += 1.0;
77
+ }
78
+ totalWeight += 1.0;
79
+ // 4. 频谱平坦度判断(权重:1.0)
80
+ // 音乐的频谱平坦度通常较低(更多音调特性)
81
+ if (f.spectralFlatness < stats.spectralFlatness.median) {
82
+ musicScore += 1.0;
83
+ }
84
+ totalWeight += 1.0;
85
+ // 5. MFCC连续性判断(权重:2.0)
86
+ // 音乐的MFCC变化通常比人声更平滑
87
+ if (idx > 0) {
88
+ const mfccVariance = mfccVariances[idx];
89
+ if (mfccVariance < avgMfccVariance * 1.2) {
90
+ const smoothness = 1 - Math.min(mfccVariance / (avgMfccVariance * 1.5), 1);
91
+ musicScore += 2.0 * smoothness;
92
+ }
93
+ }
94
+ else {
95
+ musicScore += 1.0; // 第一帧给一半分数
96
+ }
97
+ totalWeight += 2.0;
98
+ // 6. 过零率判断(权重:0.5)
99
+ // 音乐通常有适中的过零率
100
+ if (f.zcr > stats.zcr.min * 2 && f.zcr < stats.zcr.median * 1.5) {
101
+ musicScore += 0.5;
102
+ }
103
+ totalWeight += 0.5;
104
+ // 7. 频谱滚降判断(权重:0.8)
105
+ // 音乐通常有更多高频内容
106
+ if (f.spectralRolloff > stats.spectralRolloff.mean * 0.8) {
107
+ musicScore += 0.8;
108
+ }
109
+ totalWeight += 0.8;
110
+ // 计算最终得分(0-1)
111
+ const finalScore = musicScore / totalWeight;
112
+ // 阈值设为0.6,即需要60%的特征符合音乐特性
113
+ return finalScore > 0.6;
114
+ });
115
+ // 第二步:平滑处理
116
+ const smoothWindowSamples = Math.floor(cfg.smoothWindowSize / (features[1].timestamp - features[0].timestamp));
117
+ const smoothed = smoothBooleanSequence(isMusicWindow, smoothWindowSamples);
118
+ // 第三步:提取连续的音乐片段
119
+ const rawSegments = [];
120
+ let segmentStart = null;
121
+ let segmentScores = [];
122
+ for (let i = 0; i < smoothed.length; i++) {
123
+ const isMusic = smoothed[i];
124
+ const timestamp = features[i].timestamp;
125
+ if (isMusic && segmentStart === null) {
126
+ segmentStart = timestamp;
127
+ segmentScores = [];
128
+ }
129
+ if (isMusic && segmentStart !== null) {
130
+ // 收集片段内的置信度分数
131
+ segmentScores.push(isMusicWindow[i] ? 1 : 0);
132
+ }
133
+ if (!isMusic && segmentStart !== null) {
134
+ const avgConfidence = segmentScores.length > 0
135
+ ? segmentScores.reduce((a, b) => a + b, 0) / segmentScores.length
136
+ : 0.8;
137
+ rawSegments.push({
138
+ startTime: segmentStart,
139
+ endTime: timestamp,
140
+ duration: timestamp - segmentStart,
141
+ confidence: avgConfidence,
142
+ });
143
+ segmentStart = null;
144
+ segmentScores = [];
145
+ }
146
+ }
147
+ if (segmentStart !== null) {
148
+ const lastTimestamp = features[features.length - 1].timestamp;
149
+ const avgConfidence = segmentScores.length > 0
150
+ ? segmentScores.reduce((a, b) => a + b, 0) / segmentScores.length
151
+ : 0.8;
152
+ rawSegments.push({
153
+ startTime: segmentStart,
154
+ endTime: lastTimestamp,
155
+ duration: lastTimestamp - segmentStart,
156
+ confidence: avgConfidence,
157
+ });
158
+ }
159
+ // 第四步:过滤太短的片段和低置信度片段
160
+ const filteredSegments = rawSegments.filter((s) => s.duration >= cfg.minSegmentDuration && s.confidence > 0.5);
161
+ // 第五步:合并相近的片段
162
+ const mergedSegments = [];
163
+ for (const segment of filteredSegments) {
164
+ if (mergedSegments.length === 0) {
165
+ mergedSegments.push(segment);
166
+ }
167
+ else {
168
+ const lastSegment = mergedSegments[mergedSegments.length - 1];
169
+ const gap = segment.startTime - lastSegment.endTime;
170
+ if (gap <= cfg.maxGapDuration) {
171
+ lastSegment.endTime = segment.endTime;
172
+ lastSegment.duration = lastSegment.endTime - lastSegment.startTime;
173
+ }
174
+ else {
175
+ mergedSegments.push(segment);
176
+ }
177
+ }
178
+ }
179
+ return mergedSegments;
180
+ }
181
+ /**
182
+ * 格式化时间为 HH:MM:SS
183
+ */
184
+ function formatTime(seconds) {
185
+ const hours = Math.floor(seconds / 3600);
186
+ const minutes = Math.floor((seconds % 3600) / 60);
187
+ const secs = Math.floor(seconds % 60);
188
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
189
+ }
190
+ //# sourceMappingURL=segmentDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmentDetector.js","sourceRoot":"","sources":["../src/segmentDetector.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "music-segment-detector",
3
+ "version": "0.1.0",
4
+ "description": "Audio music segment detection library - Automatically detect music segments from WAV audio files",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "keywords": [
20
+ "audio",
21
+ "music",
22
+ "detection",
23
+ "segment",
24
+ "analysis",
25
+ "mfcc",
26
+ "audio-features",
27
+ "wav",
28
+ "music-detection",
29
+ "audio-analysis"
30
+ ],
31
+ "author": "",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": ""
36
+ },
37
+ "dependencies": {
38
+ "meyda": "^5.6.3",
39
+ "wav-decoder": "^1.3.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.11.5",
43
+ "typescript": "^5.3.3"
44
+ },
45
+ "engines": {
46
+ "node": ">=16.0.0"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc",
50
+ "watch": "tsc --watch",
51
+ "release": "pnpm run build && pnpm publish --access public"
52
+ }
53
+ }