fix: tự động dịch chuyển thanh cuộn xuống dưới cùng
This commit is contained in:
+37
-8
@@ -3090,6 +3090,12 @@ const App = () => {
|
||||
const [aiProvider, setAiProvider] = useState('OpenAI');
|
||||
const [aiModel, setAiModel] = useState('GPT-4o');
|
||||
const [aiActionLog, setAiActionLog] = useState([]);
|
||||
const actionLogContainerRef = useRef(null);
|
||||
useEffect(() => {
|
||||
if (actionLogContainerRef.current) {
|
||||
actionLogContainerRef.current.scrollTop = actionLogContainerRef.current.scrollHeight;
|
||||
}
|
||||
}, [aiActionLog]);
|
||||
const [aiProcessing, setAiProcessing] = useState(false);
|
||||
const [selectedProviderId, setSelectedProviderId] = useState('');
|
||||
const [exportSettings, setExportSettings] = useState({
|
||||
@@ -7627,7 +7633,10 @@ const App = () => {
|
||||
exportAudio: async (args) => {
|
||||
const tid = args.track_id || selectedTrackId;
|
||||
const track = tid && tracks.find(t => t.id === tid);
|
||||
if (!track || !track.buffer) return { success: false, error: 'No track or audio data' };
|
||||
if (!track) return { success: false, error: 'No track found' };
|
||||
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
|
||||
if (clips.length === 0) return { success: false, error: 'Track has no audio clips' };
|
||||
const totalDuration = Math.max(...clips.map(c => (c.startTime || 0) + (c.buffer ? c.buffer.duration / (c.speed || 1.0) : 0)));
|
||||
const barDur = 60 / parseInt(bpm || 120) * 4;
|
||||
const sel = selectionRef.current;
|
||||
let rawStart, rawEnd;
|
||||
@@ -7639,17 +7648,36 @@ const App = () => {
|
||||
else if (args.length_bars !== undefined) rawEnd = (rawStart || 0) + args.length_bars * barDur;
|
||||
else if (args.end_bar !== undefined) rawEnd = args.end_bar * barDur;
|
||||
else if (sel.end !== null && sel.end > rawStart) rawEnd = sel.end;
|
||||
else rawEnd = track.buffer.duration;
|
||||
else rawEnd = totalDuration;
|
||||
if (rawEnd <= rawStart) return { success: false, error: 'Export range is empty or invalid.' };
|
||||
const ctx = getAudioContext();
|
||||
const sr = parseInt(args.sample_rate || '44100');
|
||||
const numCh = args.channels === 'mono' ? 1 : (track.buffer.numberOfChannels || 2);
|
||||
const firstBuffer = clips.find(c => c.buffer)?.buffer;
|
||||
const numCh = args.channels === 'mono' ? 1 : (firstBuffer ? firstBuffer.numberOfChannels : 2);
|
||||
const bd = parseInt(args.bit_depth || '16');
|
||||
const fmt = args.format || 'wav';
|
||||
const offlineCtx = new OfflineAudioContext(numCh, Math.ceil(sr * Math.min(rawEnd - rawStart, track.buffer.duration)), sr);
|
||||
const source = offlineCtx.createBufferSource();
|
||||
source.buffer = track.buffer;
|
||||
source.start(0, rawStart, rawEnd - rawStart);
|
||||
source.connect(offlineCtx.destination);
|
||||
const renderLength = rawEnd - rawStart;
|
||||
const offlineCtx = new OfflineAudioContext(numCh, Math.ceil(sr * renderLength), sr);
|
||||
clips.forEach(clip => {
|
||||
if (!clip.buffer) return;
|
||||
const clipStart = clip.startTime || 0;
|
||||
const clipDuration = clip.buffer.duration / (clip.speed || 1.0);
|
||||
const clipEnd = clipStart + clipDuration;
|
||||
if (clipEnd <= rawStart || clipStart >= rawEnd) return;
|
||||
const source = offlineCtx.createBufferSource();
|
||||
source.buffer = clip.buffer;
|
||||
source.playbackRate.value = clip.speed || 1.0;
|
||||
source.connect(offlineCtx.destination);
|
||||
if (rawStart < clipStart) {
|
||||
const delay = clipStart - rawStart;
|
||||
const playDur = Math.min(clipDuration, rawEnd - clipStart);
|
||||
source.start(delay, 0, playDur * (clip.speed || 1.0));
|
||||
} else {
|
||||
const offsetInClip = rawStart - clipStart;
|
||||
const playDur = Math.min(clipEnd - rawStart, renderLength);
|
||||
source.start(0, offsetInClip * (clip.speed || 1.0), playDur * (clip.speed || 1.0));
|
||||
}
|
||||
});
|
||||
const renderedBuffer = await offlineCtx.startRendering();
|
||||
const len = renderedBuffer.length;
|
||||
const bps = bd / 8;
|
||||
@@ -8784,6 +8812,7 @@ const App = () => {
|
||||
"data-lucide": "list",
|
||||
className: "w-3 h-3"
|
||||
}), " Action Log")), /*#__PURE__*/React.createElement("div", {
|
||||
ref: actionLogContainerRef,
|
||||
className: "flex-1 overflow-y-auto no-scrollbar bg-[#0f0f0f] rounded border border-zinc-800 select-text"
|
||||
}, aiActionLog.length === 0 ? /*#__PURE__*/React.createElement("div", {
|
||||
className: "text-xs text-zinc-600 italic select-text"
|
||||
|
||||
Reference in New Issue
Block a user