Files
ep-133-project-export/src/lib/transformers/webView.ts

141 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-07-13 04:39:10 +02:00
import * as Sentry from '@sentry/react';
import { Note, Pad, ProjectRawData } from '../../types/types';
import { getSampleName } from '../exporters/utils';
import { noteNumberToName } from '../parsers';
import { findPad, findSoundByPad, findSoundIdByPad } from '../utils';
export type ViewNote = Note & { name: string };
export type ViewPattern = {
pad: string;
bars: number;
soundName: string;
notes: ViewNote[];
group: string;
padNumber: number;
midiChannel: number;
soundId: number;
};
export type ViewScene = {
name: string;
patterns: ViewPattern[];
maxBars: number;
};
export type ViewPad = Pad;
export type ViewData = {
pads: Record<string, ViewPad[]>;
scenes: ViewScene[];
scenesSettings: ProjectRawData['scenesSettings'];
};
function webViewTransformer(data: ProjectRawData): ViewData {
const { pads, scenes } = data;
const newScenes: ViewScene[] = [];
const usedPads = new Set<string>();
if (import.meta.env.DEV) {
console.log(data);
}
// construct new scenes array
// and collect the used pads
scenes.forEach((scene, idx) => {
newScenes[idx] = {
name: scene.name,
maxBars: Math.max(
1,
...scene.patterns.map((pattern) => pattern.bars),
...Object.values(scene.patternEvents).map((pattern) => pattern?.bars || 0),
),
2026-07-13 04:39:10 +02:00
patterns: [],
};
for (const pattern of scene.patterns) {
if (pattern.notes.length > 0) {
usedPads.add(pattern.pad);
}
}
});
// also add pads that have samples assigned (even without patterns)
for (const group in pads) {
pads[group].forEach((pad) => {
2026-07-13 04:39:10 +02:00
if (pad.soundId > 0) {
usedPads.add(`${group}${pad.pad - 1}`);
2026-07-13 04:39:10 +02:00
}
});
}
newScenes.forEach((scene, idx) => {
// make sure each scene have the same tracks/pads
usedPads.forEach((pad) => {
const patternByPad = scene.patterns.find((p) => p.pad === pad);
if (!patternByPad) {
const group = pad[0];
const padNumber = parseInt(pad.slice(1), 10);
const soundId = findSoundIdByPad(pad, pads) || 0;
const sound = findSoundByPad(pad, pads, data.sounds);
const padObject = findPad(pad, pads);
scene.patterns.push({
pad,
notes: [],
bars: 0,
group,
padNumber,
soundName: getSampleName(sound?.meta?.name, soundId, false),
midiChannel: padObject?.midiChannel || 0,
soundId,
});
}
});
// copy notes to exiting patterns
scenes[idx].patterns.forEach((pattern) => {
const patternInScene = scene.patterns.find((p) => p.pad === pattern.pad);
if (!patternInScene) {
return;
}
patternInScene.notes = pattern.notes
.map((note) => ({
...note,
name: noteNumberToName(note.note),
}))
.reduce((acc, note) => {
const existingNoteInThisPosition = acc.find((n) => n.position === note.position);
if (existingNoteInThisPosition) {
existingNoteInThisPosition.name = `${existingNoteInThisPosition.name},${note.name}`;
return acc;
}
acc.push({ ...note });
return acc;
}, [] as ViewNote[]);
patternInScene.bars = pattern.bars;
});
scene.patterns.sort((a, b) =>
a.pad.localeCompare(b.pad, undefined, { numeric: true, sensitivity: 'base' }),
);
});
Sentry.setContext('webViewData', {
pads,
scenes: newScenes,
scenesSettings: data.scenesSettings,
});
return {
pads,
scenes: newScenes,
scenesSettings: data.scenesSettings,
};
}
export default webViewTransformer;