feat: VSTi autosample -> SF2/SF3 (tools/autosample_vsti.py) + bit_depth 16/24/32 render/export WAV (render_engine, plugins API, audio_editor, app.jsx encoders) + tests + task/walkthrough docs (53)
This commit is contained in:
+12
-7
@@ -11352,6 +11352,7 @@ const ExportModal = ({ open, onClose, exportSettings, setExportSettings, isExpor
|
||||
<option value="8">8</option>
|
||||
<option value="16">16</option>
|
||||
<option value="24">24</option>
|
||||
<option value="32">32</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -13856,7 +13857,7 @@ const MediaExplorerPanel = ({ height, clipboardRef, active }) => {
|
||||
const fid = f.file_id || f.fileId;
|
||||
if (!fid) { setPeaks(null); return; }
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE_URL}/api/v1/audio/waveform/${fid}?num_peaks=600`);
|
||||
const resp = await window.SonicAPI.authFetch(`${API_BASE_URL}/api/v1/audio/waveform/${fid}?num_peaks=600`);
|
||||
const data = await resp.json();
|
||||
if (selectTokenRef.current !== token) return;
|
||||
setPeaks(data.peaks || []);
|
||||
@@ -13916,7 +13917,7 @@ const MediaExplorerPanel = ({ height, clipboardRef, active }) => {
|
||||
setComputerMode('server');
|
||||
setComputerRoots(null);
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE_URL}/api/v1/media/computer`);
|
||||
const resp = await window.SonicAPI.authFetch(`${API_BASE_URL}/api/v1/media/computer`);
|
||||
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||
const data = await resp.json();
|
||||
const roots = data.roots || [];
|
||||
@@ -13977,7 +13978,7 @@ const MediaExplorerPanel = ({ height, clipboardRef, active }) => {
|
||||
const path = entry.path || entry;
|
||||
if (!path) return null;
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE_URL}/api/v1/media/browse?path=${encodeURIComponent(path)}`);
|
||||
const resp = await window.SonicAPI.authFetch(`${API_BASE_URL}/api/v1/media/browse?path=${encodeURIComponent(path)}`);
|
||||
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||
const data = await resp.json();
|
||||
setComputerPath(data.path);
|
||||
@@ -14119,7 +14120,7 @@ const MediaExplorerPanel = ({ height, clipboardRef, active }) => {
|
||||
}
|
||||
const url = filePreviewUrl(f);
|
||||
if (!url) return null;
|
||||
const resp = await fetch(url);
|
||||
const resp = await window.SonicAPI.authFetch(url);
|
||||
return await resp.arrayBuffer();
|
||||
};
|
||||
|
||||
@@ -24354,12 +24355,12 @@ const App = () => {
|
||||
}
|
||||
if (mef.file_id || mef.fileId) {
|
||||
const fid = mef.file_id || mef.fileId;
|
||||
const resp = await fetch(`${API_BASE_URL}/api/v1/audio/download/${fid}`);
|
||||
const resp = await window.SonicAPI.authFetch(`${API_BASE_URL}/api/v1/audio/download/${fid}`);
|
||||
const blob = await resp.blob();
|
||||
return new File([blob], mef.name || mef.original_name || fid, { type: blob.type || 'audio/wav' });
|
||||
}
|
||||
if (mef.path) {
|
||||
const resp = await fetch(`${API_BASE_URL}/api/v1/media/file?path=${encodeURIComponent(mef.path)}`);
|
||||
const resp = await window.SonicAPI.authFetch(`${API_BASE_URL}/api/v1/media/file?path=${encodeURIComponent(mef.path)}`);
|
||||
const blob = await resp.blob();
|
||||
return new File([blob], mef.name || mef.path.split(/[\\/]/).pop(), { type: blob.type || 'application/octet-stream' });
|
||||
}
|
||||
@@ -25040,6 +25041,8 @@ const App = () => {
|
||||
for (let ch = 0; ch < outChannels; ch++) {
|
||||
const s = Math.max(-1, Math.min(1, stereoBuf[i * 2 + ch]));
|
||||
if (bitDepth === 16) view.setInt16(o, Math.floor(s < 0 ? s * 0x8000 : s * 0x7FFF), true);
|
||||
else if (bitDepth === 24) { const v24 = Math.floor(s < 0 ? s * 0x800000 : s * 0x7FFFFF); view.setUint8(o, v24 & 0xFF); view.setUint8(o + 1, (v24 >> 8) & 0xFF); view.setUint8(o + 2, (v24 >> 16) & 0xFF); }
|
||||
else if (bitDepth === 32) view.setInt32(o, Math.floor(s < 0 ? s * 0x80000000 : s * 0x7FFFFFFF), true);
|
||||
else view.setUint8(o, Math.floor((s + 1) * 127.5), true);
|
||||
o += bytesPerSample;
|
||||
}
|
||||
@@ -25362,6 +25365,8 @@ const App = () => {
|
||||
view.setUint8(offset, val24 & 0xFF);
|
||||
view.setUint8(offset + 1, val24 >> 8 & 0xFF);
|
||||
view.setUint8(offset + 2, val24 >> 16 & 0xFF);
|
||||
} else if (bitDepth === 32) {
|
||||
view.setInt32(offset, Math.floor(sample < 0 ? sample * 0x80000000 : sample * 0x7FFFFFFF), true);
|
||||
}
|
||||
offset += bytesPerSample;
|
||||
}
|
||||
@@ -28697,7 +28702,7 @@ STRICT CONSTRAINTS:
|
||||
value: exportSettings.bitDepth,
|
||||
onChange: e => setExportSettings(p => ({ ...p, bitDepth: e.target.value })),
|
||||
className: "w-full bg-[#141414] border border-zinc-800 rounded px-1 py-0.5 text-xs text-zinc-300 focus:outline-none"
|
||||
}, /*#__PURE__*/React.createElement("option", { value: "8" }, "8"), /*#__PURE__*/React.createElement("option", { value: "16" }, "16"), /*#__PURE__*/React.createElement("option", { value: "24" }, "24")))) : /*#__PURE__*/React.createElement("div", {
|
||||
}, /*#__PURE__*/React.createElement("option", { value: "8" }, "8"), /*#__PURE__*/React.createElement("option", { value: "16" }, "16"), /*#__PURE__*/React.createElement("option", { value: "24" }, "24"), /*#__PURE__*/React.createElement("option", { value: "32" }, "32")))) : /*#__PURE__*/React.createElement("div", {
|
||||
className: "grid grid-cols-2 gap-1"
|
||||
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", {
|
||||
className: "block text-[7px] text-zinc-500 font-bold uppercase mb-0.5"
|
||||
|
||||
Reference in New Issue
Block a user