Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

マルチトラック:再生・書き出しに対応 #2163

Merged
merged 21 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f2f4737
WIP
sevenc-nanashi Jul 7, 2024
9ae329d
Add: とりあえず再生できるように
sevenc-nanashi Jul 7, 2024
f4a565c
Add: 全書き出しをマルチトラックに対応
sevenc-nanashi Jul 7, 2024
0e56e64
Change: previewSynthをglobalChannelStripに直接繋ぐようにする
sevenc-nanashi Jul 8, 2024
7a51bc7
Change: generateDefaultSongFileNameをstoreの外に出す
sevenc-nanashi Jul 10, 2024
6eccab6
Change: watchStoreStatePluginにする
sevenc-nanashi Jul 10, 2024
d3aa785
Merge: main -> multitrack/play
sevenc-nanashi Jul 10, 2024
9ef350b
Change: fileHelperから持ってくるようにする
sevenc-nanashi Jul 10, 2024
7e03f14
Change: convertToWavFileDataを外に出す
sevenc-nanashi Jul 10, 2024
878df69
Change: watchStoreStatePlugins -> watchStoreStatePlugin
sevenc-nanashi Jul 10, 2024
a6d4cb2
Code: コメントを追加
sevenc-nanashi Jul 10, 2024
1670a27
Change: RENDER内を良い感じにする
sevenc-nanashi Jul 11, 2024
bf2e192
Delete: nextTickを削除
sevenc-nanashi Jul 11, 2024
6425a21
Merge: main -> multitrack/play
sevenc-nanashi Jul 18, 2024
b1f3da2
Code: コメントの内容を変える
sevenc-nanashi Jul 19, 2024
7b72645
Fix: 2回設定していたのを削除
sevenc-nanashi Jul 20, 2024
9f477bb
Change: globalChannelStrip -> mainChannelStrip
sevenc-nanashi Jul 21, 2024
f11d894
Change: createAudioPlayerSequenceを戻す
sevenc-nanashi Jul 21, 2024
c35937b
Change: shouldPlayTracks内のフィルタに任せる
sevenc-nanashi Jul 21, 2024
13d344d
Change: getterにする
sevenc-nanashi Jul 21, 2024
d665551
Add: limiterを追加
sevenc-nanashi Jul 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createApp } from "vue";
import { createGtm } from "@gtm-support/vue-gtm";
import { Quasar, Dialog, Loading, Notify } from "quasar";
import iconSet from "quasar/icon-set/material-icons";
import { store, storeKey } from "./store";
import { store, watchStoreStatePlugin, storeKey } from "./store";
import { ipcMessageReceiver } from "./plugins/ipcMessageReceiverPlugin";
import { hotkeyPlugin } from "./plugins/hotkeyPlugin";
import App from "@/components/App.vue";
Expand All @@ -18,6 +18,7 @@ window.dataLayer = [];

createApp(App)
.use(store, storeKey)
.use(watchStoreStatePlugin, { store })
.use(
createGtm({
id: import.meta.env.VITE_GTM_CONTAINER_ID ?? "GTM-DUMMY",
Expand Down
30 changes: 28 additions & 2 deletions src/sing/audioRendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,20 +871,24 @@ export class PolySynth implements Instrument {

export type ChannelStripOptions = {
readonly volume?: number;
readonly pan?: number;
readonly mute?: boolean;
};

/**
* ミキサーの1チャンネル分の機能を提供します。
*/
export class ChannelStrip {
private readonly gainNode: GainNode;
private readonly muteGainNode: GainNode;
private readonly panNode: StereoPannerNode;

get input(): AudioNode {
return this.gainNode;
return this.muteGainNode;
}

get output(): AudioNode {
return this.gainNode;
return this.panNode;
}

get volume() {
Expand All @@ -894,9 +898,31 @@ export class ChannelStrip {
this.gainNode.gain.value = value;
}

get mute() {
return this.muteGainNode.gain.value === 0;
}
set mute(value: boolean) {
this.muteGainNode.gain.value = value ? 0 : 1;
}

get pan() {
return this.panNode.pan.value;
}
set pan(value: number) {
this.panNode.pan.value = value;
}

constructor(audioContext: BaseAudioContext, options?: ChannelStripOptions) {
this.gainNode = new GainNode(audioContext);
this.muteGainNode = new GainNode(audioContext);
this.panNode = new StereoPannerNode(audioContext);

this.muteGainNode.connect(this.gainNode);
this.gainNode.connect(this.panNode);

this.gainNode.gain.value = options?.volume ?? 0.1;
this.muteGainNode.gain.value = options?.mute ? 0 : 1;
this.panNode.pan.value = options?.pan ?? 0;
}
}

Expand Down
56 changes: 56 additions & 0 deletions src/sing/convertToWavFileData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export const convertToWavFileData = (audioBuffer: AudioBuffer) => {
const bytesPerSample = 4; // Float32
const formatCode = 3; // WAVE_FORMAT_IEEE_FLOAT

const numberOfChannels = audioBuffer.numberOfChannels;
const numberOfSamples = audioBuffer.length;
const sampleRate = audioBuffer.sampleRate;
const byteRate = sampleRate * numberOfChannels * bytesPerSample;
const blockSize = numberOfChannels * bytesPerSample;
const dataSize = numberOfSamples * numberOfChannels * bytesPerSample;

const buffer = new ArrayBuffer(44 + dataSize);
const dataView = new DataView(buffer);

let pos = 0;
const writeString = (value: string) => {
for (let i = 0; i < value.length; i++) {
dataView.setUint8(pos, value.charCodeAt(i));
pos += 1;
}
};
const writeUint32 = (value: number) => {
dataView.setUint32(pos, value, true);
pos += 4;
};
const writeUint16 = (value: number) => {
dataView.setUint16(pos, value, true);
pos += 2;
};
const writeSample = (offset: number, value: number) => {
dataView.setFloat32(pos + offset * 4, value, true);
};

writeString("RIFF");
writeUint32(36 + dataSize); // RIFFチャンクサイズ
writeString("WAVE");
writeString("fmt ");
writeUint32(16); // fmtチャンクサイズ
writeUint16(formatCode);
writeUint16(numberOfChannels);
writeUint32(sampleRate);
writeUint32(byteRate);
writeUint16(blockSize);
writeUint16(bytesPerSample * 8); // 1サンプルあたりのビット数
writeString("data");
writeUint32(dataSize);

for (let i = 0; i < numberOfChannels; i++) {
const channelData = audioBuffer.getChannelData(i);
for (let j = 0; j < numberOfSamples; j++) {
writeSample(j * numberOfChannels + i, channelData[j]);
}
}

return buffer;
};
13 changes: 12 additions & 1 deletion src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InjectionKey } from "vue";
import { InjectionKey, Plugin } from "vue";
import { createStore, Store, useStore as baseUseStore } from "./vuex";

import {
Expand All @@ -23,6 +23,7 @@ import {
singingStore,
singingCommandStoreState,
singingCommandStore,
singingStorePlugin,
} from "./singing";
import { projectStoreState, projectStore } from "./project";
import { uiStoreState, uiStore } from "./ui";
Expand Down Expand Up @@ -412,6 +413,16 @@ export const store = createStore<State, AllGetters, AllActions, AllMutations>({
strict: !isProduction,
});

// Storeをwatchするためのプラグインをまとめたもの。
export const watchStoreStatePlugin: Plugin = {
install(
app,
{ store }: { store: Store<State, AllGetters, AllActions, AllMutations> },
) {
singingStorePlugin(store);
},
};

export const useStore = (): Store<
State,
AllGetters,
Expand Down
Loading
Loading