解決したいこと
rails側に保存した音声ファイルをReact側のwavesurferで使用したいです。
環境
・dockerを使用して、バックエンド側(RoR)とフロントエンド側{React TypeScript *(wavesurferなどの一部はJavaScript)}に分けて開発を行っています。OSはWindowsですが、wsl2のUbuntu20.04で開発を行っています。
・Rails側では、CarrierwaveとActive_storageを試してみましたが、どちらもrails側に保存した音声ファイルをReact側のwavesurferで使用した時のみ上手くWevesurferで描画できませんでした。現在はActive_storageを使用しています。
発生している問題
エラーは発生しないのですが、rails側に保存した音声ファイルをReact側のwavesurferで使用した時にのみWevesurferの波形が描写されません。
1 その場でアップロードしたファイルをwevesurferで使う場合
こちらのサイトを参考にさせて頂き、そのまま使用しています。
https://www.wizard-notes.com/entry/javascript/react-wavesurfer-js
js
1export function WSF() { 2 3const waveformRef = useRef(null); 4 var context = null; 5 console.log(waveformRef) 6 7 const handlePlayPause = () => { 8 waveformRef.current.playPause(); 9 console.log("handlePlayPause") 10 } 11 12 const handleChangeFile = (e) => { 13 if (context == null) { 14 window.AudioContext = window.AudioContext || window.webkitAudioContext; 15 context = new AudioContext(); 16 17 waveformRef.current = WaveSurfer.create({ 18 container: waveformRef.current, 19 audioContext: context, 20 }); 21 console.log(waveformRef); 22 } 23 24 const file = e.target.files[0] 25 console.log(file) 26 if (file) { 27 const fileUrl = URL.createObjectURL(file) 28 waveformRef.current.load(fileUrl); 29 console.log(fileUrl) 30 } 31 } 32 33 return ( 34 <div> 35 <div ref={waveformRef}></div> 36 <input type="file" accept="audio/*" onChange={(e) => handleChangeFile(e)} /> 37 <button onClick={handlePlayPause}>Play/Pause</button> 38 </div> 39 ); 40}
この場合、ファイルを選択すると、wevesurferで正常に波形が描写されます。
1` このコードを参考にしてローカル(Rails側)のファイルを使用できるか?
以下のコードを全て試してみましたが、どれもエラーは出ないものの、波形が描写されませんでした。また、useRefを使用する都合上、ロードボタンをクリックしてから波形が描写されるという仕様になっています。また、同じ部分は省略しました。
そのままパラメータを渡した場合
js
1// そのままパラメータを渡した場合。p_fileが取得した音声ファイルのパラメータ 2export function WSF_stock(p_file) { 3 const waveformRef = useRef(null); 4 var context = null; 5 6 const handlePlayPause = () => { 7 waveformRef.current.playPause(); 8 console.log("handlePlayPause") 9 } 10 11 const handleChangeFile = (e) => { 12 13 if (context == null) { 14 // context = new AudioContext(); 15 window.AudioContext = window.AudioContext || window.webkitAudioContext; 16 context = new AudioContext(); 17 18 waveformRef.current = WaveSurfer.create({ 19 container: waveformRef.current, 20 audioContext: context, 21 }); 22// ここから 23 console.log(waveformRef) 24 console.log(p_file) 25 waveformRef.current.load(p_file); 26// ここまでを入れ替えていきます 27 28 } 29 } 30 return ( 31 <div> 32 <div ref={waveformRef}></div> 33 <button onClick={(e) => handleChangeFile(e)}>ロード</button> 34 <button onClick={handlePlayPause}>Play/Pause</button> 35 </div> 36 ); 37 } 38 39// console 40{file: '/rails/active_storage/blobs/redirect/eyJfcmFpbHMiO…%E3%82%B9%E3%83%AC%E3%83%8A%E3%82%B0%E3%82%B5.mp3'} 41file: "/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEUT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b196a9a15bdc6cd3711c34dd46ca1a27962720a3/%E3%83%AF%E3%82%B9%E3%83%AC%E3%83%8A%E3%82%B0%E3%82%B5.mp3" 42[[Prototype]]: Object 43このようにデータは渡っている 44
一旦ファイルオブジェクトを生成してからそれをURLにしてロード
js
1const new_file = new File([p_file], "保存された音声",{type: "audio/mpeg"}) 2const NewFile = URL.createObjectURL(new_file) 3waveformRef.current.load(NewFile); 4 5// console 6 7{current: WaveSurfer}current: WaveSurfer {_disabledEventEmissions: Array(0), handlers: null, defaultParams: {…}, backends: {…}, util: {…}, …}[[Prototype]]: Object 8wavesurfer.jsx:69 {file: '/rails/active_storage/blobs/redirect/eyJfcmFpbHMiO…%E3%82%B9%E3%83%AC%E3%83%8A%E3%82%B0%E3%82%B5.mp3'}file: "/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19-- 9ad9777f976b16c2879d73e76e7d749f1ba2c1293/%E3%83%AF%E3%82%B9%E3%83%AC%E3%83%8A%E3%82%B0%E3%82%B5.mp3"[[Prototype]]: Object 10wavesurfer.jsx:85
blobにして渡してみる
js
1const blob = new Blob([p_file], {type: "audio/mpeg"}) 2const NewFile = URL.createObjectURL(blob) 3console.log(NewFile) 4waveformRef.current.load(NewFile);
ファイルにしてみる
js
1const Newfile = new File([p_file], "保存された音声",{type: "audio/mpeg"}) 2waveformRef.current.load(NewFile);
ロードの仕方を変える
waveformRef.current.load(); => waveformRef.current.loadBlob();
自分の考察
・このコードの場合、ファイルをそのまま直接アップロードした場合にしかwevesurferの描写を受け付けないという結論に至りました。ファイルを直接渡すと、
js
1File {name: 'Night_Sea.mp3', lastModified: 1647685053601, lastModifiedDate: Sat Mar 19 2022 19:17:33 GMT+0900 (日本標準時), webkitRelativePath: '', size: 947012, …}lastModified: 1647685053601lastModifiedDate: Sat Mar 19 2022 19:17:33 GMT+0900 (日本標準時) {}name: "Night_Sea.mp3"size: 947012type: "audio/mpeg"webkitRelativePath: ""[[Prototype]]: File 2wavesurfer.jsx:35 blob:http://localhost:4000/8d6613ff-4084-4952-a218-6c97701ddb0c
このように描写されます。一応これと同じように、一旦保存しているデータをファイルにして入れてみましたがなぜか上手く描写されませんでした。
また、ここで詰まってしまったため、新しい方法を模索していると、
https://www.npmjs.com/package/wavesurfer-react#wavesurfer
このWevesurferをReactで使えるようにするJSライブラリーを見つけたので、使用してみることにしました。
2 ローカル(フロントエンド側)に保存した音声ファイルを再生する場合
*このライブラリーは新しいため、参考記事が少なく、手探りで仕様を何とか把握しようとしたため、間違った認識をしているかもしれません
https://codesandbox.io/s/wavesurfer-react-20-gqvb6
・このライブラリーの仕様は恐らく、フロントエンド側のパブリックディレクトリにある音声ファイルのみにアクセス可能だと思われます。
・試しに別のディレクトリ(imgなど)を作成して音声ファイルを移動させてみたところ、相対パスが正しくても音声ファイルを読み込まないことを確認しました。
・私の作成しているアプリの挙動としては、
1 React側で音声ファイルなどのデータを受け取り、axiosでrails側にPostし保存。音声ファイルはActiveStrageに保存される。
2 Getリクエストを送ってrails側からデータ取得
3 取得したデータを使用してwevesurferにデータを入れて波形を描写
という挙動をして欲しいため、このライブラリーの使用を断念致しました。
また、一応ActiveStrageを使用する際に参考にしたサイトを載せておきます
https://dev.to/jblengino510/uploading-files-in-a-react-rails-app-using-active-storage-201c
その他
・一応rails側に保存した音声ファイルをReact側のwavesurferで使用する時にのみ、波形が描写されないだけで、データの受け渡しは出来ていると思われます。他にnameやanswerなどのカラムが存在しますが、上手く値を取得できていました。
・フロントエンド側とバックエンド側に分割しないで使用した際(これと別のアプリ)は上手く描写できていました。
・問題解決のために必要な重要な情報(ファイルなど)が抜けているかもしれません。その際はご指摘いただけますと幸いです。
・何かしらアドバイスがあればよろしくお願いいたします。
追記
マルチポストをしています。不快に思われたら申し訳ございません。
https://ja.stackoverflow.com/questions/90418/rails%e5%81%b4%e3%81%ab%e4%bf%9d%e5%ad%98%e3%81%97%e3%81%9f%e9%9f%b3%e5%a3%b0%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92react%e5%81%b4%e3%81%aewavesurfer%e3%81%a7%e4%bd%bf%e7%94%a8%e3%81%97%e3%81%9f%e3%81%84

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。