Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8875

node-lameを使ってelectronでwav→mp3に変換するデスクトップアプリを作ってみた

$
0
0
はじめに こんにちは!qiita初投稿です。 自分は組み込み系を2年くらいやっているプログラマーです。 仕事では主にvisual c++ や c#.netを使ってます。 元々web系に興味があったので、組み込み系で行ったデスクトップアプリ制作の経験が活かせるelectronを勉強しています。 ある程度勉強して、node-lameというライブラリを使ってwavファイルをmp3にエンコードするちょっとしたアプリを作ってみたので解説してみます。 node-lameとは lameというオープンソースのエンコーダーをnodejs環境で使えるようにしたライブラリのようです。 wavやmp2をmp3にエンコードしたり、デコードしたりと音声ファイルの変換ができるみたいです。 (node-lame公式画像) wavなどの音声ファイルはヘッダー部分、データの部分とフォーマットが決まっていて、プログラムで読み込むときはヘッダーがどこまでか、データ部はどんな形式でサイズはどうなのかを考えて読み込むことになります。 データを正確に読み込むのはかなり大変でそれを変換するとなると一つなにかがずれるだけでエラーが起きたりしてかなり大変です。 このライブラリを使うだけで安全に読み込んでくれるのでかなり便利ですね。 基本的な使い方 エンコードのサンプルコードをちょこっと解説します。 1.まずrequireでnode-lameを読み込む const Lame = require("node-lame").Lame; 2.出力先のパスとファイル名、ビットレートなどを設定してインスタンスを作成する output:のあとにパスとファイル名を設定します。ここに適当な変数をセットしておくと、guiでユーザーが設定したパスとかを使えますね。 const encoder = new Lame({ output: "./audio-files/demo.mp3", bitrate: 192, }).setFile("./audio-files/demo.wav"); 3.encode()またはdecode()で変換する then()で異常系を書いておくと、成功したら「エンコードが終わりました」的なメッセージを出して、失敗したらエラーメッセージを出したりできますね。 encoder .encode() .then(() => { // Encoding finished }) .catch((error) => { // Something went wrong }); 作ったもの electronといえば、atom,vscodeなどですね。 組み込み系のプログラマーとしてはラズベリーパイのosの焼き込みに仕えるetcherがelectronを使ったソフトとして思い浮かびます。 etcherのUIはすごくシンプルで好きなので、etcherを参考にシンプルなUIを作ってみました。 githubリポジトリ 完全に見た目通りです。「SELECT WAV FILES」でwavファイルをダイアログで選択します。 それから 「ENCODE TO MP3!」 をクリックしたら選択したwavファイルがmp3に変換されて、出力先のパスに保存されます。 ソース 大まかな動作の流れはmainWindow.htmlからボタンの入力をmain.jsが受け取り、ダイアログを開いたり、変換をする。 変換が上手くいったらメッセージを表示するです。 main.js const electron = require("electron"); const url = require('url'); const Lame = require("node-lame").Lame; const {app, BrowserWindow, ipcMain, dialog, Menu} = electron; const path = require('path'); let { cnvfilename,filename} = ''; let mainWindow; app.on('ready', () => { mainWindow = new BrowserWindow({ width: 650, height: 500, webPreferences: { nodeIntegration: true, contextIsolation: false } }); // Load html into window mainWindow.loadURL(url.format({ pathname: path.join(__dirname, 'mainWindow.html'), protocol:'file:', slashes: true })); // Quit app when closed mainWindow.on('closed', function(){ app.quit(); }); mainWindow.removeMenu(); }); // Catch Convert ipcMain.on('Convert',function(e){ // Replace wav to mp3 (WIP) filename = filename.replace('wav', 'mp3'); // Set output location const output = "./output/" + filename; // Set target file by path const encoder = new Lame({ output: output, bitrate: 128, }).setFile(cnvfilename); // Encode by node-lame encoder.encode() .then(() => { // Encoding finished console.log("success"); e.reply('convert-reply', 'complete!') }) .catch((error) => { // Something went wrong console.log(error); }); }); // File-open dialog ipcMain.handle('file-open', async (event) => { const filepaths = dialog.showOpenDialogSync(mainWindow, { buttonLabel: 'open', filters: [ { name: 'Audiofiles', extensions: ['audiofiles', 'wav'] }, ], properties:[ 'openFile', 'createDirectory', ] }); // when closes dialog without opening a file if( filepaths === undefined ){ return({status: undefined}); } // get files contents try { const filepath = filepaths[0]; cnvfilename = filepath; filename = path.basename(filepath); return({ status: true, path: path, name: filename }); } catch(error) { return({status:false, message:error.message}); } }); mainWindow.html <!DOCTYPE html> <html lang="en"> <head> <title>AudioConv</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="./css/main.css"> </head> <body> <div class="container"> <form> <div class="row pt-160"> <div class="col s6 center-align"> <i class="medium material-icons icon-white">add_box</i> <pre class="m-12" id="input-file"> </pre> <button id="filesSelect" type="button" class="waves-effect waves-light btn">Select Wav files</button> </div> <div class="col s6 center-align"> <i class="medium material-icons icon-white">cached</i> <pre class="m-12" id="after-convert"> </pre> <button id="convert" type="button" class="waves-effect waves-light btn">Encode to MP3!</button> </div> </div> </form> </div> <script> const electron = require('electron'); const { ipcRenderer } = electron; // Get html elements const form = document.querySelector('form'); const BtnFilesSelect = document.getElementById('filesSelect'); const BtnConvert = document.getElementById('convert'); // Adding Eventlistner to each button BtnFilesSelect.addEventListener('click', filesSelect); BtnConvert.addEventListener('click', convert); // File open dialog event function filesSelect(e){ ipcRenderer.invoke('file-open') .then((result) => { if(result.status == undefined){ return(false); } if(!result.status){ alert('Could not open the file\n${result.message}'); return(false); } document.getElementById('input-file').innerHTML = result.name; }) } // Convert button function convert(e){ ipcRenderer.send('Convert'); } // Show complete message when converting is finished ipcRenderer.on('convert-reply', (e, message) => { document.getElementById('after-convert').innerHTML = message; }) </script> </body> </html> 今後やりたいこと とりあえずまずは変換できるファイルを増やしたいですね。 それからまだipcRendererやipcMainの仕様をしっかり把握していないのでその辺を掘り下げていきたいですね。

Viewing all articles
Browse latest Browse all 8875

Trending Articles