@onjmin/dtm 0.1.98 → 0.1.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -942,6 +942,12 @@ type DawOptions = {
942
942
  onPlayDrum?: (e: PlayDrumEvent) => void;
943
943
  /** 初回ユーザー操作時に呼ばれる(AudioContextのresume等に使う) */
944
944
  onResumeAudio?: () => void | Promise<void>;
945
+ /**
946
+ * 「MIDI / MML 出力」パネルの「WAV書き出し」ボタン押下時に呼ばれる。
947
+ * 未指定ならボタン自体を表示しない(ライブラリは音を出さないため、書き出し処理は
948
+ * AudioContextを持つ利用側 = createDtmStudio 等が担う)。
949
+ */
950
+ onExportWav?: () => void | Promise<void>;
945
951
  /** 再生の基準クロック秒。既定 performance.now()/1000。利用側は audioCtx.currentTime を返す */
946
952
  getAudioTime?: () => number;
947
953
  /**
@@ -2295,6 +2301,15 @@ type DtmStudio = {
2295
2301
  * MediaRecorder のストリーム合成(canvas + audio)に使えます。
2296
2302
  */
2297
2303
  getAudioStreamTrack: () => MediaStreamTrack;
2304
+ /**
2305
+ * WAV書き出し用の録音を開始する(マスタバス最終段=リバーブ/ディレイ/コンプ/
2306
+ * リミッター/フェード適用後のPCMをそのままタップする)。
2307
+ * 呼び出し側で再生(daw.play() 等)を開始し、曲が終わったら stopWavRecording を呼ぶ想定。
2308
+ * 実際の再生と同じ経路を録るため等速(曲の長さ分だけ実時間がかかる)。
2309
+ */
2310
+ startWavRecording: () => void;
2311
+ /** startWavRecording で開始した録音を止め、16bit PCM WAVのBlobを返す。 */
2312
+ stopWavRecording: () => Promise<Blob>;
2298
2313
  /** 歌声合成ヘルパ(klatt + koe音源)。 */
2299
2314
  singingVoices: SingingVoices;
2300
2315
  /** 編集UI(mountDAW)を音・歌声込みでマウントする。 */
@@ -2425,4 +2440,17 @@ declare const createSynth: (ctx: AudioContext, destination?: AudioNode, tone?: S
2425
2440
 
2426
2441
  declare const VOICE_IMAGES: Record<string, string>;
2427
2442
 
2428
- export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
2443
+ /**
2444
+ * PCM(Float32、チャンネル別)から 16bit PCM WAV の Blob を作る、依存なしの小さなエンコーダ。
2445
+ * 追加ライブラリなしで完結させたいので RIFF/WAVE ヘッダを手書きしている。
2446
+ */
2447
+ /**
2448
+ * チャンネルごとの Float32Array(同じ長さ)から 16bit PCM WAV の Blob を生成する。
2449
+ * @param channels 各チャンネルのサンプル列(例: [left, right])
2450
+ * @param sampleRate サンプリングレート(Hz)
2451
+ */
2452
+ declare const encodeWavPCM16: (channels: Float32Array[], sampleRate: number) => Blob;
2453
+ /** Float32Array のチャンクを1本へ連結する。 */
2454
+ declare const concatFloat32: (chunks: Float32Array[]) => Float32Array;
2455
+
2456
+ export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
package/dist/index.d.ts CHANGED
@@ -942,6 +942,12 @@ type DawOptions = {
942
942
  onPlayDrum?: (e: PlayDrumEvent) => void;
943
943
  /** 初回ユーザー操作時に呼ばれる(AudioContextのresume等に使う) */
944
944
  onResumeAudio?: () => void | Promise<void>;
945
+ /**
946
+ * 「MIDI / MML 出力」パネルの「WAV書き出し」ボタン押下時に呼ばれる。
947
+ * 未指定ならボタン自体を表示しない(ライブラリは音を出さないため、書き出し処理は
948
+ * AudioContextを持つ利用側 = createDtmStudio 等が担う)。
949
+ */
950
+ onExportWav?: () => void | Promise<void>;
945
951
  /** 再生の基準クロック秒。既定 performance.now()/1000。利用側は audioCtx.currentTime を返す */
946
952
  getAudioTime?: () => number;
947
953
  /**
@@ -2295,6 +2301,15 @@ type DtmStudio = {
2295
2301
  * MediaRecorder のストリーム合成(canvas + audio)に使えます。
2296
2302
  */
2297
2303
  getAudioStreamTrack: () => MediaStreamTrack;
2304
+ /**
2305
+ * WAV書き出し用の録音を開始する(マスタバス最終段=リバーブ/ディレイ/コンプ/
2306
+ * リミッター/フェード適用後のPCMをそのままタップする)。
2307
+ * 呼び出し側で再生(daw.play() 等)を開始し、曲が終わったら stopWavRecording を呼ぶ想定。
2308
+ * 実際の再生と同じ経路を録るため等速(曲の長さ分だけ実時間がかかる)。
2309
+ */
2310
+ startWavRecording: () => void;
2311
+ /** startWavRecording で開始した録音を止め、16bit PCM WAVのBlobを返す。 */
2312
+ stopWavRecording: () => Promise<Blob>;
2298
2313
  /** 歌声合成ヘルパ(klatt + koe音源)。 */
2299
2314
  singingVoices: SingingVoices;
2300
2315
  /** 編集UI(mountDAW)を音・歌声込みでマウントする。 */
@@ -2425,4 +2440,17 @@ declare const createSynth: (ctx: AudioContext, destination?: AudioNode, tone?: S
2425
2440
 
2426
2441
  declare const VOICE_IMAGES: Record<string, string>;
2427
2442
 
2428
- export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
2443
+ /**
2444
+ * PCM(Float32、チャンネル別)から 16bit PCM WAV の Blob を作る、依存なしの小さなエンコーダ。
2445
+ * 追加ライブラリなしで完結させたいので RIFF/WAVE ヘッダを手書きしている。
2446
+ */
2447
+ /**
2448
+ * チャンネルごとの Float32Array(同じ長さ)から 16bit PCM WAV の Blob を生成する。
2449
+ * @param channels 各チャンネルのサンプル列(例: [left, right])
2450
+ * @param sampleRate サンプリングレート(Hz)
2451
+ */
2452
+ declare const encodeWavPCM16: (channels: Float32Array[], sampleRate: number) => Blob;
2453
+ /** Float32Array のチャンクを1本へ連結する。 */
2454
+ declare const concatFloat32: (chunks: Float32Array[]) => Float32Array;
2455
+
2456
+ export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
package/dist/index.js CHANGED
@@ -56,6 +56,7 @@ __export(index_exports, {
56
56
  buildDrumPatternJson: () => buildDrumPatternJson,
57
57
  buildNameToKeyMapping: () => buildNameToKeyMapping,
58
58
  collectPitchTokens: () => collectPitchTokens,
59
+ concatFloat32: () => concatFloat32,
59
60
  createAudioContext: () => createAudioContext,
60
61
  createDtmStudio: () => createDtmStudio,
61
62
  createKlattVoice: () => createKlattVoice,
@@ -75,6 +76,7 @@ __export(index_exports, {
75
76
  drawSelectedNotes: () => drawSelectedNotes,
76
77
  drawSelectionRect: () => drawSelectionRect,
77
78
  encodeMml: () => encodeMml,
79
+ encodeWavPCM16: () => encodeWavPCM16,
78
80
  exportMIDI: () => exportMIDI,
79
81
  extractDrumPatternFromNotes: () => extractDrumPatternFromNotes,
80
82
  extractMidiDrumPattern: () => extractMidiDrumPattern,
@@ -11752,6 +11754,7 @@ var buildUI = (target, options) => {
11752
11754
  <div class="dtm-row">
11753
11755
  <button class="dtm-btn dtm-btn--accent" data-dtm="export-midi">MIDI\u51FA\u529B</button>
11754
11756
  <button class="dtm-btn dtm-btn--success" data-dtm="generate-mml">MML\u751F\u6210</button>
11757
+ <button class="dtm-btn dtm-btn--primary dtm-hidden" data-dtm="export-wav">WAV\u66F8\u304D\u51FA\u3057</button>
11755
11758
  </div>
11756
11759
  <div class="dtm-row">
11757
11760
  <button class="dtm-btn dtm-btn--primary" data-dtm="drum-json-export" title="\u8AAD\u307F\u8FBC\u3093\u3060MIDI\u306E\u30C9\u30E9\u30E0\u5B9A\u7FA9\u3092JSON\u51FA\u529B">\u30C9\u30E9\u30E0JSON\u51FA\u529B</button>
@@ -11895,6 +11898,7 @@ var buildUI = (target, options) => {
11895
11898
  macroHarmonic: sel("macro-harmonic"),
11896
11899
  macroMono: sel("macro-mono"),
11897
11900
  exportMidiBtn: sel("export-midi"),
11901
+ exportWavBtn: sel("export-wav"),
11898
11902
  drumJsonExportBtn: sel("drum-json-export"),
11899
11903
  drumJsonOutput: sel("drum-json-output"),
11900
11904
  drumJsonStatus: sel("drum-json-status"),
@@ -17153,6 +17157,12 @@ var mountDAW = (target, options = {}) => {
17153
17157
  a.click();
17154
17158
  URL.revokeObjectURL(url2);
17155
17159
  });
17160
+ if (options.onExportWav) {
17161
+ refs.exportWavBtn.classList.remove("dtm-hidden");
17162
+ refs.exportWavBtn.addEventListener("click", () => {
17163
+ void options.onExportWav?.();
17164
+ });
17165
+ }
17156
17166
  const copy = (text, btn) => {
17157
17167
  navigator.clipboard?.writeText(text);
17158
17168
  btn.classList.add("dtm-btn--success");
@@ -19029,6 +19039,64 @@ var SoundFont_list = new class {
19029
19039
  }
19030
19040
  }();
19031
19041
 
19042
+ // src/wav-export.ts
19043
+ var floatTo16BitPCM = (view, offset, input) => {
19044
+ for (let i2 = 0; i2 < input.length; i2++, offset += 2) {
19045
+ const s = Math.max(-1, Math.min(1, input[i2]));
19046
+ view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
19047
+ }
19048
+ };
19049
+ var writeString = (view, offset, str) => {
19050
+ for (let i2 = 0; i2 < str.length; i2++) {
19051
+ view.setUint8(offset + i2, str.charCodeAt(i2));
19052
+ }
19053
+ };
19054
+ var encodeWavPCM16 = (channels, sampleRate) => {
19055
+ const numChannels = channels.length;
19056
+ const numFrames = channels[0]?.length ?? 0;
19057
+ const bytesPerSample = 2;
19058
+ const blockAlign = numChannels * bytesPerSample;
19059
+ const dataSize = numFrames * blockAlign;
19060
+ const buffer = new ArrayBuffer(44 + dataSize);
19061
+ const view = new DataView(buffer);
19062
+ writeString(view, 0, "RIFF");
19063
+ view.setUint32(4, 36 + dataSize, true);
19064
+ writeString(view, 8, "WAVE");
19065
+ writeString(view, 12, "fmt ");
19066
+ view.setUint32(16, 16, true);
19067
+ view.setUint16(20, 1, true);
19068
+ view.setUint16(22, numChannels, true);
19069
+ view.setUint32(24, sampleRate, true);
19070
+ view.setUint32(28, sampleRate * blockAlign, true);
19071
+ view.setUint16(32, blockAlign, true);
19072
+ view.setUint16(34, bytesPerSample * 8, true);
19073
+ writeString(view, 36, "data");
19074
+ view.setUint32(40, dataSize, true);
19075
+ if (numChannels === 1) {
19076
+ floatTo16BitPCM(view, 44, channels[0]);
19077
+ } else {
19078
+ let offset = 44;
19079
+ for (let i2 = 0; i2 < numFrames; i2++) {
19080
+ for (let c = 0; c < numChannels; c++) {
19081
+ const s = Math.max(-1, Math.min(1, channels[c][i2]));
19082
+ view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
19083
+ offset += 2;
19084
+ }
19085
+ }
19086
+ }
19087
+ return new Blob([buffer], { type: "audio/wav" });
19088
+ };
19089
+ var concatFloat32 = (chunks) => {
19090
+ const total = chunks.reduce((sum, c) => sum + c.length, 0);
19091
+ const out = new Float32Array(total);
19092
+ let offset = 0;
19093
+ for (const c of chunks) {
19094
+ out.set(c, offset);
19095
+ offset += c.length;
19096
+ }
19097
+ return out;
19098
+ };
19099
+
19032
19100
  // src/studio.ts
19033
19101
  var import_meta = {};
19034
19102
  var SOUNDFONT_NAME2 = "FluidR3_GM_sf2_file";
@@ -19506,6 +19574,28 @@ var createDtmStudio = async (options = {}) => {
19506
19574
  },
19507
19575
  onPlayNote: playNote4,
19508
19576
  onPlayDrum: playDrum,
19577
+ onExportWav: async () => {
19578
+ if (!daw) return;
19579
+ daw.stop();
19580
+ await resumeAudio();
19581
+ startWavRecording();
19582
+ await daw.play();
19583
+ await new Promise((resolve) => {
19584
+ const iv = setInterval(() => {
19585
+ if (daw.getPlaybackState() !== "playing") {
19586
+ clearInterval(iv);
19587
+ resolve();
19588
+ }
19589
+ }, 200);
19590
+ });
19591
+ const blob2 = await stopWavRecording();
19592
+ const url2 = URL.createObjectURL(blob2);
19593
+ const a = document.createElement("a");
19594
+ a.href = url2;
19595
+ a.download = "dtm.wav";
19596
+ a.click();
19597
+ URL.revokeObjectURL(url2);
19598
+ },
19509
19599
  singingVoices,
19510
19600
  parseMidi,
19511
19601
  onInstrumentChange: handleInstrumentChange,
@@ -20093,11 +20183,48 @@ var createDtmStudio = async (options = {}) => {
20093
20183
  const getAudioStreamTrack = () => {
20094
20184
  return createMediaStreamDestination().stream.getAudioTracks()[0];
20095
20185
  };
20186
+ let wavTap = null;
20187
+ const startWavRecording = () => {
20188
+ if (wavTap) return;
20189
+ const bufferSize = 4096;
20190
+ const processor = audioCtx.createScriptProcessor(bufferSize, 2, 2);
20191
+ const chunksL = [];
20192
+ const chunksR = [];
20193
+ processor.onaudioprocess = (e) => {
20194
+ chunksL.push(new Float32Array(e.inputBuffer.getChannelData(0)));
20195
+ chunksR.push(
20196
+ new Float32Array(
20197
+ e.inputBuffer.getChannelData(
20198
+ e.inputBuffer.numberOfChannels > 1 ? 1 : 0
20199
+ )
20200
+ )
20201
+ );
20202
+ };
20203
+ const silentSink = audioCtx.createGain();
20204
+ silentSink.gain.value = 0;
20205
+ fadeGain.connect(processor);
20206
+ processor.connect(silentSink);
20207
+ silentSink.connect(audioCtx.destination);
20208
+ wavTap = { processor, silentSink, chunksL, chunksR };
20209
+ };
20210
+ const stopWavRecording = async () => {
20211
+ if (!wavTap) throw new Error("[dtm] startWavRecording \u304C\u547C\u3070\u308C\u3066\u3044\u307E\u305B\u3093");
20212
+ const { processor, silentSink, chunksL, chunksR } = wavTap;
20213
+ fadeGain.disconnect(processor);
20214
+ processor.disconnect(silentSink);
20215
+ silentSink.disconnect(audioCtx.destination);
20216
+ wavTap = null;
20217
+ const left = concatFloat32(chunksL);
20218
+ const right = concatFloat32(chunksR);
20219
+ return encodeWavPCM16([left, right], audioCtx.sampleRate);
20220
+ };
20096
20221
  return {
20097
20222
  audioContext: audioCtx,
20098
20223
  masterGain,
20099
20224
  createMediaStreamDestination,
20100
20225
  getAudioStreamTrack,
20226
+ startWavRecording,
20227
+ stopWavRecording,
20101
20228
  singingVoices,
20102
20229
  mountEditor,
20103
20230
  mountPlayer,
@@ -20160,6 +20287,7 @@ var createDtmStudio = async (options = {}) => {
20160
20287
  buildDrumPatternJson,
20161
20288
  buildNameToKeyMapping,
20162
20289
  collectPitchTokens,
20290
+ concatFloat32,
20163
20291
  createAudioContext,
20164
20292
  createDtmStudio,
20165
20293
  createKlattVoice,
@@ -20179,6 +20307,7 @@ var createDtmStudio = async (options = {}) => {
20179
20307
  drawSelectedNotes,
20180
20308
  drawSelectionRect,
20181
20309
  encodeMml,
20310
+ encodeWavPCM16,
20182
20311
  exportMIDI,
20183
20312
  extractDrumPatternFromNotes,
20184
20313
  extractMidiDrumPattern,
package/dist/index.mjs CHANGED
@@ -11621,6 +11621,7 @@ var buildUI = (target, options) => {
11621
11621
  <div class="dtm-row">
11622
11622
  <button class="dtm-btn dtm-btn--accent" data-dtm="export-midi">MIDI\u51FA\u529B</button>
11623
11623
  <button class="dtm-btn dtm-btn--success" data-dtm="generate-mml">MML\u751F\u6210</button>
11624
+ <button class="dtm-btn dtm-btn--primary dtm-hidden" data-dtm="export-wav">WAV\u66F8\u304D\u51FA\u3057</button>
11624
11625
  </div>
11625
11626
  <div class="dtm-row">
11626
11627
  <button class="dtm-btn dtm-btn--primary" data-dtm="drum-json-export" title="\u8AAD\u307F\u8FBC\u3093\u3060MIDI\u306E\u30C9\u30E9\u30E0\u5B9A\u7FA9\u3092JSON\u51FA\u529B">\u30C9\u30E9\u30E0JSON\u51FA\u529B</button>
@@ -11764,6 +11765,7 @@ var buildUI = (target, options) => {
11764
11765
  macroHarmonic: sel("macro-harmonic"),
11765
11766
  macroMono: sel("macro-mono"),
11766
11767
  exportMidiBtn: sel("export-midi"),
11768
+ exportWavBtn: sel("export-wav"),
11767
11769
  drumJsonExportBtn: sel("drum-json-export"),
11768
11770
  drumJsonOutput: sel("drum-json-output"),
11769
11771
  drumJsonStatus: sel("drum-json-status"),
@@ -17022,6 +17024,12 @@ var mountDAW = (target, options = {}) => {
17022
17024
  a.click();
17023
17025
  URL.revokeObjectURL(url2);
17024
17026
  });
17027
+ if (options.onExportWav) {
17028
+ refs.exportWavBtn.classList.remove("dtm-hidden");
17029
+ refs.exportWavBtn.addEventListener("click", () => {
17030
+ void options.onExportWav?.();
17031
+ });
17032
+ }
17025
17033
  const copy = (text, btn) => {
17026
17034
  navigator.clipboard?.writeText(text);
17027
17035
  btn.classList.add("dtm-btn--success");
@@ -18898,6 +18906,64 @@ var SoundFont_list = new class {
18898
18906
  }
18899
18907
  }();
18900
18908
 
18909
+ // src/wav-export.ts
18910
+ var floatTo16BitPCM = (view, offset, input) => {
18911
+ for (let i2 = 0; i2 < input.length; i2++, offset += 2) {
18912
+ const s = Math.max(-1, Math.min(1, input[i2]));
18913
+ view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
18914
+ }
18915
+ };
18916
+ var writeString = (view, offset, str) => {
18917
+ for (let i2 = 0; i2 < str.length; i2++) {
18918
+ view.setUint8(offset + i2, str.charCodeAt(i2));
18919
+ }
18920
+ };
18921
+ var encodeWavPCM16 = (channels, sampleRate) => {
18922
+ const numChannels = channels.length;
18923
+ const numFrames = channels[0]?.length ?? 0;
18924
+ const bytesPerSample = 2;
18925
+ const blockAlign = numChannels * bytesPerSample;
18926
+ const dataSize = numFrames * blockAlign;
18927
+ const buffer = new ArrayBuffer(44 + dataSize);
18928
+ const view = new DataView(buffer);
18929
+ writeString(view, 0, "RIFF");
18930
+ view.setUint32(4, 36 + dataSize, true);
18931
+ writeString(view, 8, "WAVE");
18932
+ writeString(view, 12, "fmt ");
18933
+ view.setUint32(16, 16, true);
18934
+ view.setUint16(20, 1, true);
18935
+ view.setUint16(22, numChannels, true);
18936
+ view.setUint32(24, sampleRate, true);
18937
+ view.setUint32(28, sampleRate * blockAlign, true);
18938
+ view.setUint16(32, blockAlign, true);
18939
+ view.setUint16(34, bytesPerSample * 8, true);
18940
+ writeString(view, 36, "data");
18941
+ view.setUint32(40, dataSize, true);
18942
+ if (numChannels === 1) {
18943
+ floatTo16BitPCM(view, 44, channels[0]);
18944
+ } else {
18945
+ let offset = 44;
18946
+ for (let i2 = 0; i2 < numFrames; i2++) {
18947
+ for (let c = 0; c < numChannels; c++) {
18948
+ const s = Math.max(-1, Math.min(1, channels[c][i2]));
18949
+ view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
18950
+ offset += 2;
18951
+ }
18952
+ }
18953
+ }
18954
+ return new Blob([buffer], { type: "audio/wav" });
18955
+ };
18956
+ var concatFloat32 = (chunks) => {
18957
+ const total = chunks.reduce((sum, c) => sum + c.length, 0);
18958
+ const out = new Float32Array(total);
18959
+ let offset = 0;
18960
+ for (const c of chunks) {
18961
+ out.set(c, offset);
18962
+ offset += c.length;
18963
+ }
18964
+ return out;
18965
+ };
18966
+
18901
18967
  // src/studio.ts
18902
18968
  var SOUNDFONT_NAME2 = "FluidR3_GM_sf2_file";
18903
18969
  var TRACK_ROLES = [
@@ -19374,6 +19440,28 @@ var createDtmStudio = async (options = {}) => {
19374
19440
  },
19375
19441
  onPlayNote: playNote4,
19376
19442
  onPlayDrum: playDrum,
19443
+ onExportWav: async () => {
19444
+ if (!daw) return;
19445
+ daw.stop();
19446
+ await resumeAudio();
19447
+ startWavRecording();
19448
+ await daw.play();
19449
+ await new Promise((resolve) => {
19450
+ const iv = setInterval(() => {
19451
+ if (daw.getPlaybackState() !== "playing") {
19452
+ clearInterval(iv);
19453
+ resolve();
19454
+ }
19455
+ }, 200);
19456
+ });
19457
+ const blob2 = await stopWavRecording();
19458
+ const url2 = URL.createObjectURL(blob2);
19459
+ const a = document.createElement("a");
19460
+ a.href = url2;
19461
+ a.download = "dtm.wav";
19462
+ a.click();
19463
+ URL.revokeObjectURL(url2);
19464
+ },
19377
19465
  singingVoices,
19378
19466
  parseMidi,
19379
19467
  onInstrumentChange: handleInstrumentChange,
@@ -19961,11 +20049,48 @@ var createDtmStudio = async (options = {}) => {
19961
20049
  const getAudioStreamTrack = () => {
19962
20050
  return createMediaStreamDestination().stream.getAudioTracks()[0];
19963
20051
  };
20052
+ let wavTap = null;
20053
+ const startWavRecording = () => {
20054
+ if (wavTap) return;
20055
+ const bufferSize = 4096;
20056
+ const processor = audioCtx.createScriptProcessor(bufferSize, 2, 2);
20057
+ const chunksL = [];
20058
+ const chunksR = [];
20059
+ processor.onaudioprocess = (e) => {
20060
+ chunksL.push(new Float32Array(e.inputBuffer.getChannelData(0)));
20061
+ chunksR.push(
20062
+ new Float32Array(
20063
+ e.inputBuffer.getChannelData(
20064
+ e.inputBuffer.numberOfChannels > 1 ? 1 : 0
20065
+ )
20066
+ )
20067
+ );
20068
+ };
20069
+ const silentSink = audioCtx.createGain();
20070
+ silentSink.gain.value = 0;
20071
+ fadeGain.connect(processor);
20072
+ processor.connect(silentSink);
20073
+ silentSink.connect(audioCtx.destination);
20074
+ wavTap = { processor, silentSink, chunksL, chunksR };
20075
+ };
20076
+ const stopWavRecording = async () => {
20077
+ if (!wavTap) throw new Error("[dtm] startWavRecording \u304C\u547C\u3070\u308C\u3066\u3044\u307E\u305B\u3093");
20078
+ const { processor, silentSink, chunksL, chunksR } = wavTap;
20079
+ fadeGain.disconnect(processor);
20080
+ processor.disconnect(silentSink);
20081
+ silentSink.disconnect(audioCtx.destination);
20082
+ wavTap = null;
20083
+ const left = concatFloat32(chunksL);
20084
+ const right = concatFloat32(chunksR);
20085
+ return encodeWavPCM16([left, right], audioCtx.sampleRate);
20086
+ };
19964
20087
  return {
19965
20088
  audioContext: audioCtx,
19966
20089
  masterGain,
19967
20090
  createMediaStreamDestination,
19968
20091
  getAudioStreamTrack,
20092
+ startWavRecording,
20093
+ stopWavRecording,
19969
20094
  singingVoices,
19970
20095
  mountEditor,
19971
20096
  mountPlayer,
@@ -20027,6 +20152,7 @@ export {
20027
20152
  buildDrumPatternJson,
20028
20153
  buildNameToKeyMapping,
20029
20154
  collectPitchTokens,
20155
+ concatFloat32,
20030
20156
  createAudioContext,
20031
20157
  createDtmStudio,
20032
20158
  createKlattVoice,
@@ -20046,6 +20172,7 @@ export {
20046
20172
  drawSelectedNotes,
20047
20173
  drawSelectionRect,
20048
20174
  encodeMml,
20175
+ encodeWavPCM16,
20049
20176
  exportMIDI,
20050
20177
  extractDrumPatternFromNotes,
20051
20178
  extractMidiDrumPattern,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "onjmin",
3
3
  "license": "MIT",
4
4
  "name": "@onjmin/dtm",
5
- "version": "0.1.98",
5
+ "version": "0.1.99",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {