[ Golang ] 1時間でできる MP3 の音楽を再生するCLIツールを作成

この記事は約10分で読めます。

今回は 1時間でできるGo言語 で mp3 を流すCLIツールを作ってみます。

音楽再生パッケージを使えば、音楽再生は簡単にできます!

 

完成品はこちらへ

完成品(github)

 

[Brainfuck]難解言語?Go言語で独自言語を作ってみる
Go言語を用いて、Brainfuckを模倣した独自言語を作ってみます。Brainfuckはぱっと見、プログラムかさえも怪しい言語ですが、チューリング完全なプログラミング言語です。この仕組みを模倣すると、簡単に独自言語ができます!ぜひ試してみてください!

 

Step1:簡単にmp3の音楽を流してみよう

今回,mp3の音声を流すために使うパッケージはこちらです!

faiface/beep
A little package that brings sound to any Go application. Suitable for playback and audio-processing. - faiface/beep

 

このパッケージを使って、音楽を流してみます

コード

package main

import (
	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"
	"github.com/faiface/beep/speaker"

	"os"
	"time"
)

func main(){
        filepath := "~/Desktop/test.mp3"
        Sound(filepath)
}

func Sound(path string) error {
	f, _ := os.Open(path)
	s, format, err := mp3.Decode(f)
	if err != nil {
		return err
	}
	err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
	if err != nil {
		return err
	}
	done := make(chan struct{})
	speaker.Play(beep.Seq(s, beep.Callback(func() {
		close(done)
	})))
	_ = <-done

	return nil
}

 

解説

1:mp3ファイルを読み込む

f, _ := os.Open(path)
s, format, err := mp3.Decode(f)

ここで、ファイルパスから、mp3を読み込む処理を入れています。

2:音声ファイルを再生する

err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
done := make(chan struct{})
speaker.Play(beep.Seq(s, beep.Callback(func() {
	close(done)
})))
_ = <-done

Initで、音声を再生する速度を設定しています。こちらは通常再生の設定を加えています。

Playは再生する設定をしています。再生が終了した時に、doneチャネルに値を送信します。

 

<-done この部分はチャネルから値が入るまでブロックします。なので、音楽が流れている間は、この部分で止まっています。終了して値が入ってくると、次の処理に移ります。

チャネルは奥が深いので、とりあえず、再生が終了するまで、ここでブロックされていると思ってください

 

4:実行

$go run main.go

Step2:cliツールを作る

cliツールを簡単に作れるパッケージはこちらです。

urfave/cli
A simple, fast, and fun package for building command line apps in Go - urfave/cli

このパッケージの使い方を簡単にご紹介します。

コード

package main

import (
	"fmt"
        "os"

	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "test"
	app.Usage = "play music"
	app.Version = "1.0.0"
	app.Commands = []cli.Command{
		{
			Name:   "play",
			Usage:  "play music",
			Action: play,
		},
	}

	app.Run(os.Args)
}

func play(c *cli.Context) {
	for _, v := range c.Args() {
		fmt.Println(v)
	}
}

解説

1:ツールの初期化、設定出力

app := cli.NewApp()
	app.Name = "test"
	app.Usage = "play music"
	app.Version = "1.0.0"
	app.Commands = []cli.Command{
		{
			Name:   "play",
			Usage:  "play music",
			Action: play,
		},
	}
  • Name:アプリの名前
  • Usage:アプリの使い方
  • Version:cliのバージョン
  • Commands:コマンドを登録する

自由に設定できます。設定した情報は、コマンドツールでよくある、-h オプションで表示できます。
試しに

$go run cli.go -h 
NAME:
   test - play music

USAGE:
   cli [global options] command [command options] [arguments...]

VERSION:
   1.0.0

COMMANDS:
   play     play music
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

こんな感じで表示されます。

次に
cli.Commandスライスには、アクション(command)を登録できます

  • Name:コマンド名
  • Usage:コマンドの使い方
  • Action:コマンドの実際の動作を設定

そして、このアクションに、

func (c *cli.Context)error

の関数を設定します。今回は、コマンドの後ろに繋げた文字を表示するアクションを設定します。

func play(c *cli.Context) {
	for _, v := range c.Args() {
		fmt.Println(v)
	}
}

2:実行

$go run cli.go play test1 test2 test3
test1 
test2
test3

こんな感じで実行されます。

Step3:組み合わせMp3を実行するCLIツールを実装する

ディレクトリ構成

.
├── mcli
│   ├── action.go
│   └── cli.go
├── cmd
│   └── music-cli.go
├── go.mod
├── go.sum
└── sound.go

補足情報

今回、mainパッケージをcmd/に追加しています。これによって、コマンドを利用するときは、

$ go get github.com/ryomak/music-cli/cmd

でインポートできます。

音楽を再生するパッケージを使いたいときは

$ go get github.com/ryomak/music-cli
/*
コード上では
import(
    sound "github.com/ryomak/music-cli"
)

で利用できます。
自分で作成した音楽を再生するパッケージ(sound.go)を他のプロジェクトでも使う時に、見やすくなります。

1:mcliパッケージ

mcliパッケージは、musicを再生するcliパッケージです!

mcli.go

package mcli

import (
	"github.com/urfave/cli"
)

func New(name, usage, version string) *cli.App {
	app := cli.NewApp()
	app.Name = name
	app.Usage = usage
	app.Version = version
	app.Commands = getCommands()
	return app
}

func getCommands() []cli.Command {
	return []cli.Command{
		{
			Name:   "play",
			Usage:  "play music",
			Action: play,
		},
	}
}

action.go

package mcli

import (
	"fmt"
	"path/filepath"

	"github.com/ryomak/musicbox/sound"
	"github.com/urfave/cli"
)

func play(c *cli.Context) {
	for _, v := range c.Args() {
		_, filename := filepath.Split(v)
		fmt.Printf("start %s... \n", filename)
		err := sound.Sound(v)
		if err != nil {
			fmt.Printf("cannot start skipping %s \n", filename)
		}
	}
}

補足情報

actionとcli設定で分けた理由としては、これからコマンドが増える時に

actionのみの設定を記述するファイルに分けておくと、あとで修正がしやすいからです。

あと、
filepath.Splitはとても便利で、入力されたファイルパスを
ディレクトリとファイル名に分けてくれます。
~/Desktop/test.go => (~/Desktop) と (test.go)

 

2:Mainパッケージ

music-cli.go

package main

import (
	"os"

	"github.com/ryomak/music-cli/mcli"
)

func main() {
  app := mcli.New("music-cli", "BGM", "1.0.0")
  app.Run(os.Args)
}

先ほど作った、mcliパッケージを読み込んで実行しています。

3:soundパッケージ

package sound

import (
	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"
	"github.com/faiface/beep/speaker"

	"os"
	"time"
)

func Sound(path string) error {
	f, _ := os.Open(path)
	s, format, err := mp3.Decode(f)
	if err != nil {
		return err
	}
	done := make(chan struct{})
	err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
	if err != nil {
		return err
	}
	speaker.Play(beep.Seq(s, beep.Callback(func() {
		close(done)
	})))
	_ = <-done

	return nil
}

実行

$go run cmd/music-cli play ~/Desktop/music.mp3
start music.mp3...

まとめ

今回はmp3を再生するcliツールを作成してみました。
簡単に作成できて、これから派生もたくさんできるので、ぜひ改良していってください!

ryomak/music-cli
example for mp3 . Contribute to ryomak/music-cli development by creating an account on GitHub.

githubにもあげています!

 

[ Golang ] Go 言語入門~ Web スクレイピング ~

それでは。

タイトルとURLをコピーしました