Skip to content

Commit bd6fc31

Browse files
refactor: 波形ピーク関連の型・変数名を変更
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent df5310a commit bd6fc31

3 files changed

Lines changed: 109 additions & 94 deletions

File tree

src/components/Sing/SequencerWaveform.vue

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import { useMounted } from "@/composables/useMounted";
1313
import { tickToBaseX, type ViewportInfo } from "@/sing/viewHelper";
1414
import { secondToTick, tickToSecond } from "@/sing/music";
1515
import {
16-
generateWaveformPeaks,
16+
generateWaveformPeaksMipmap,
1717
resamplePeaks,
18-
type WaveformPeaks,
18+
type WaveformPeaksMipmap,
1919
} from "@/sing/waveformPeaks";
2020
import { Mutex } from "@/helpers/mutex";
2121
import { createLogger } from "@/helpers/log";
@@ -99,13 +99,15 @@ const audioEvents = computed<ReadonlyMap<AudioEventId, AudioEvent>>(() => {
9999
return events;
100100
});
101101
102-
// AudioBufferから算出した波形ピークのMap
103-
const peaksMap = ref<ReadonlyMap<AudioEventId, WaveformPeaks>>(new Map());
102+
// AudioBufferから算出した波形ピークmipmapのMap
103+
const peaksMipmaps = ref<ReadonlyMap<AudioEventId, WaveformPeaksMipmap>>(
104+
new Map(),
105+
);
104106
105-
const updatePeaksMap = () => {
107+
const updatePeaksMipmaps = () => {
106108
const audioEventsValue = audioEvents.value;
107109
108-
const tempMap = new Map(peaksMap.value);
110+
const tempMap = new Map(peaksMipmaps.value);
109111
110112
// 不要なキーを削除
111113
for (const eventId of tempMap.keys()) {
@@ -114,16 +116,16 @@ const updatePeaksMap = () => {
114116
}
115117
}
116118
117-
// 新規キーについてpeaksを生成
119+
// 新規キーについてpeaksMipmapを生成
118120
// NOTE: sequenceIdに対応するAudioBufferは不変なので、既存キーの再計算は不要
119121
for (const [eventId, event] of audioEventsValue) {
120122
if (!tempMap.has(eventId)) {
121123
// mipmapの最小のバケツサイズは、最大ズーム時にも解像度が足りる 16 を採用
122-
tempMap.set(eventId, generateWaveformPeaks(event.buffer, 16));
124+
tempMap.set(eventId, generateWaveformPeaksMipmap(event.buffer, 16));
123125
}
124126
}
125127
126-
peaksMap.value = tempMap;
128+
peaksMipmaps.value = tempMap;
127129
};
128130
129131
// 描画用の波形データのMap
@@ -136,7 +138,7 @@ const waveformDataMutex = new Mutex({ maxPending: 1 });
136138
137139
const computeWaveformData = (
138140
event: AudioEvent,
139-
peaks: WaveformPeaks,
141+
peaksMipmap: WaveformPeaksMipmap,
140142
scaleXValue: number,
141143
temposValue: readonly Tempo[],
142144
tpqnValue: number,
@@ -167,7 +169,10 @@ const computeWaveformData = (
167169
);
168170
}
169171
170-
const { minValues, maxValues } = resamplePeaks(peaks, pixelBoundarySamples);
172+
const { minValues, maxValues } = resamplePeaks(
173+
peaksMipmap,
174+
pixelBoundarySamples,
175+
);
171176
172177
return {
173178
startX: startScreenXAtZeroOffset,
@@ -179,7 +184,7 @@ const computeWaveformData = (
179184
180185
const updateWaveformDataMap = async () => {
181186
const audioEventsValue = audioEvents.value;
182-
const peaksMapValue = peaksMap.value;
187+
const peaksMipmapsValue = peaksMipmaps.value;
183188
const scaleXValue = scaleX.value;
184189
// NOTE: Tempoが型レベルでイミュータブルになっていないので、cloneしている
185190
const temposValue = cloneWithUnwrapProxy(tempos.value);
@@ -212,10 +217,10 @@ const updateWaveformDataMap = async () => {
212217
// 新規キーについて描画用の波形データを計算
213218
for (const [key, { eventId, event }] of keyedEvents) {
214219
if (!tempMap.has(key)) {
215-
const peaks = getOrThrow(peaksMapValue, eventId);
220+
const peaksMipmap = getOrThrow(peaksMipmapsValue, eventId);
216221
const waveformData = computeWaveformData(
217222
event,
218-
peaks,
223+
peaksMipmap,
219224
scaleXValue,
220225
temposValue,
221226
tpqnValue,
@@ -232,13 +237,13 @@ const { mounted } = useMounted();
232237
// NOTE: mountedをwatchしているので、onMountedの直後に必ず1回実行される
233238
watch([mounted, audioEvents], ([mountedValue]) => {
234239
if (mountedValue) {
235-
updatePeaksMap();
240+
updatePeaksMipmaps();
236241
}
237242
});
238243
239244
// NOTE: mountedをwatchしているので、onMountedの直後に必ず1回実行される
240245
watch(
241-
[mounted, audioEvents, peaksMap, scaleX, tempos, tpqn],
246+
[mounted, audioEvents, peaksMipmaps, scaleX, tempos, tpqn],
242247
async ([mountedValue]) => {
243248
if (mountedValue) {
244249
try {

src/sing/waveformPeaks.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { getLast } from "@/sing/utility";
1111
/**
1212
* mipmapのレベル。バケツサイズと、各バケツのmin/max値を保持する。
1313
*/
14-
type WaveformMipmapLevel = {
14+
type WaveformPeaksMipmapLevel = {
1515
readonly bucketSize: number;
1616
readonly minBuckets: Float32Array;
1717
readonly maxBuckets: Float32Array;
@@ -21,7 +21,7 @@ type WaveformMipmapLevel = {
2121
* 波形ピークのmipmap。
2222
* 先頭のレベルが最も細かいレベルで、以降はバケツサイズの昇順に並ぶ。
2323
*/
24-
export type WaveformPeaks = readonly WaveformMipmapLevel[];
24+
export type WaveformPeaksMipmap = readonly WaveformPeaksMipmapLevel[];
2525

2626
/**
2727
* 波形ピークをリサンプルしたもの。
@@ -38,10 +38,10 @@ export type ResampledPeaks = {
3838
* @param minBucketSize 最小のバケツサイズ。1以上の整数でなければならない。
3939
* @returns 生成されたピークのmipmap。レベルはバケツサイズで昇順にソートされている。
4040
*/
41-
export function generateWaveformPeaks(
41+
export function generateWaveformPeaksMipmap(
4242
audioBuffer: AudioBuffer,
4343
minBucketSize: number,
44-
): WaveformPeaks {
44+
): WaveformPeaksMipmap {
4545
if (!Number.isInteger(minBucketSize) || minBucketSize < 1) {
4646
throw new Error("minBucketSize must be a positive integer.");
4747
}
@@ -72,7 +72,7 @@ export function generateWaveformPeaks(
7272
baseMaxBuckets[bucketIndex] = max;
7373
}
7474

75-
const levels: WaveformMipmapLevel[] = [
75+
const levels: WaveformPeaksMipmapLevel[] = [
7676
{
7777
bucketSize: minBucketSize,
7878
minBuckets: baseMinBuckets,
@@ -116,7 +116,7 @@ export function generateWaveformPeaks(
116116
* 各区間に対応するサンプル範囲を境界配列で指定して、ピークをリサンプルする。
117117
* 区間ごとに最適なmipmapレベルを選択するため、サンプル幅が不均等でも適切な解像度になる。
118118
*
119-
* @param peaks リサンプル元のピークmipmap。
119+
* @param peaksMipmap リサンプル元のピークmipmap。
120120
* レベルはバケツサイズで昇順にソートされていなければならない。
121121
* @param binBoundarySamples 各区間の境界をサンプル位置で表した配列。
122122
* `binBoundarySamples[i]` 以上 `binBoundarySamples[i + 1]` 未満が区間 `i` のサンプル範囲。
@@ -127,23 +127,25 @@ export function generateWaveformPeaks(
127127
* @returns 各区間のmin/max値。
128128
*/
129129
export function resamplePeaks(
130-
peaks: WaveformPeaks,
130+
peaksMipmap: WaveformPeaksMipmap,
131131
binBoundarySamples: number[],
132132
): ResampledPeaks {
133-
if (peaks.length === 0) {
134-
throw new Error("peaks must have at least one level.");
133+
if (peaksMipmap.length === 0) {
134+
throw new Error("peaksMipmap must have at least one level.");
135135
}
136-
for (const level of peaks) {
136+
for (const level of peaksMipmap) {
137137
if (level.minBuckets.length !== level.maxBuckets.length) {
138138
throw new Error("minBuckets and maxBuckets must have the same length.");
139139
}
140140
if (level.minBuckets.length === 0) {
141141
throw new Error("every level must have at least one bucket.");
142142
}
143143
}
144-
for (let i = 1; i < peaks.length; i++) {
145-
if (peaks[i].bucketSize <= peaks[i - 1].bucketSize) {
146-
throw new Error("peaks levels must be in ascending order of bucketSize.");
144+
for (let i = 1; i < peaksMipmap.length; i++) {
145+
if (peaksMipmap[i].bucketSize <= peaksMipmap[i - 1].bucketSize) {
146+
throw new Error(
147+
"peaksMipmap levels must be in ascending order of bucketSize.",
148+
);
147149
}
148150
}
149151
if (binBoundarySamples.length < 2) {
@@ -165,8 +167,8 @@ export function resamplePeaks(
165167
}
166168
// bucketSize <= samplesPerBin を満たす最大の bucketSize のレベルを選ぶ
167169
// どのレベルも条件を満たさないときは、最も細かいレベルを使う
168-
let selectedLevel = peaks[0];
169-
for (const level of peaks) {
170+
let selectedLevel = peaksMipmap[0];
171+
for (const level of peaksMipmap) {
170172
if (level.bucketSize > samplesPerBin) {
171173
break;
172174
}

0 commit comments

Comments
 (0)