实战代码项目学 Go 语言:音乐播放器[亲测有效]

go (80) 2023-04-12 13:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说实战代码项目学 Go 语言:音乐播放器[亲测有效],希望能够帮助你!!!。

需求规划

  • 目标

设计实现一个简单的播放器。

  • 调用方式

命令行调用

  • 主要功能
  1. 查看、添加和删除里面的音乐曲目
  2. 播放音乐
  3. 支持 MP3 和 WAV
  4. 可扩展更多音频格式
  5. 退出程序
  • 程序结构

实战代码项目学 Go 语言:音乐播放器[亲测有效]_https://bianchenghao6.com/blog_go_第1张

全部源码在 src 文件夹下,mplayer 里是主程序,mlib 中是对播放器的控制逻辑,mp 中是对播放操作的逻辑。

代码实现

在代码实现中,按照程序结构分为 3 个部分实现:

  • 主程序
  • 增删改查逻辑
  • 操作逻辑

主程序

在主程序中,主要的功能点有 1 个:

  • 命令行交互
func main()  {
	fmt.Println("Enter following commands to control the player:" +
		"lib list -- View the existing music lib lib add <name><artist><source><type> -- Add a music to the music lib")

	lib = mlib.NewMusicManager()
	r := bufio.NewReader(os.Stdin) // 接收命令行输入

	for {
		fmt.Print("Enter command-> ")
		rawLine, _, _ := r.ReadLine() // 接收命令行输入
		line := string(rawLine)
		if line == "q" || line == "e" { // 解析命令
			break
		}
		tokens := strings.Split(line, " ")
		if tokens[0] == "lib" { // 解析命令
			handleLibCommands(tokens)
		} else if tokens[0] == "play" { // 解析命令
			handleLibCommand(tokens)
		} else { // 解析命令
			fmt.Println("Unrecognized command:", tokens[0])
		}
	}
}

当是 lib 命令时,通过解析第 1 个参数,来确定下一步的增删改查。

func handleLibCommands(tokens []string)  {
	switch tokens[1] {
	case "list": // 列举所有列表
		for i:=0; i<lib.Len(); i++ {
			e, _ := lib.Get(i)
			fmt.Println(i+1, ":", e.Name, e.Artist, e.Source, e.Type)
		}
	case "add": // 添加一条
		if len(tokens) == 6 {
			id++
			lib.Add(&mlib.MusicEntry{strconv.Itoa(id), tokens[2], tokens[3], tokens[4], tokens[5]})
		} else {
			fmt.Println("USAGE: lib add <name><artist><source><type>")
		}
	case "remove": // 删除一条
		if len(tokens) == 3 {
			//lib.RemoveByName(tokens[2])
		} else {
			fmt.Println("USAGE: lib remove <name>")
		}
	default:
			fmt.Println("Unrecognized lib command:", tokens[1])
	}

}

当是 play 命令时,通过解析参数,来执行播放操作

func handleLibCommand(tokens []string) {
	if len(tokens) != 2 {
		fmt.Println("USAGE: play <name>")
		return
	}

	e := lib.Find(tokens[1])
	if e == nil {
		fmt.Println("The music", tokens[1], "does not exist.")
		return
	}

	mp.Play(e.Source, e.Type)
}

增删改查逻辑

增删改查逻辑是由 mlib.MusicManager 来实现的。它的组成内容包括 2 部分:

  • 成员变量
  • 成员方法

成员变量中包含了一个 MusicEntry 类型的变量

musics []MusicEntry

MusicEntry 中记录了歌曲的一些基本信息。

type MusicEntry struct {
	Id string
	Name string
	Artist string
	Source string
	Type string
}

成员方法中定义了一系列增删改查的方法:

func (m *MusicManager) Len() int {
	return len(m.musics)
}

func (m *MusicManager) Get(index int) (music *MusicEntry, err error) {
	if index < 0 || index >= len(m.musics) {
		return nil, errors.New("Index out of range.")
	}
	return &m.musics[index], nil
}

func (m *MusicManager) Find(name string) *MusicEntry {
	if len(m.musics) == 0 {
		return nil
	}

	for _, m := range m.musics {
		if m.Name == name {
			return &m
		}
	}
	return nil
}

func (m *MusicManager) Add(music *MusicEntry) {
	m.musics = append(m.musics, *music)
}

func (m *MusicManager) Remove(index int) *MusicEntry{
	if index < 0 || index >= len(m.musics) {
		return nil
	}

	removedMusic := &m.musics[index]

	m.musics = append(m.musics[:index], m.musics[index+1:]...)

	return removedMusic
}

同时定义了 MusicManager 的构造函数,在其中初始化了 MusicEntry 变量为 0。

func NewMusicManager() *MusicManager {
	return &MusicManager{make([]MusicEntry, 0)}
}

操作逻辑是由 mp.Play 实现的,mp.Play 中 Player 定义了一个接口 Play(source string)

type Player interface {
	Play(source string)
}

mp.mp3 和 mp.wav 分别都完整的实现了 Player 的全部接口。因此,继承了 Player 。

package mp

import (
	"fmt"
	"time"
)

type MP3Player struct {
	stat int
	progress int
}

func (p *MP3Player) Play(source string) {
	fmt.Println("Playing MP3 music", source)

	p.progress = 0

	for p.progress < 100 {
		time.Sleep(100 * time.Microsecond)
		fmt.Println(".")
		p.progress += 10
	}

	fmt.Println("\n Finished playing", source)
}

package mp

import (
	"fmt"
	"time"
)

type WAVPlayer struct {
	stat int
	progress int
}

func (w *WAVPlayer) Play(source string) {
	fmt.Println("Playing WAV music", source)

	w.progress = 0

	for w.progress < 100 {
		time.Sleep(100 * time.Microsecond)
		fmt.Println(".")
		w.progress += 10
	}

	fmt.Println("\n Finished playing", source)
}

在 mp.Play 中 Player 类型变量调用 Play 函数时,就会根据设定类型执行。

package mp

import "fmt"

type Player interface {
	Play(source string)
}

func Play(source, mtype string)  {
	var p Player

	switch mtype {
	    case "MP3":
			p = &MP3Player{}
		case "WAV":
			p = &WAVPlayer{}
		default:
			fmt.Println("Unsupported music type", mtype)
			return
	}

	p.Play(source)
}

构建执行

构建的过程使用 go run 执行:

go run mplayer.go 

期间会出现命令行交互窗口,提示按照指定的命令格式来操作播放。

经过以上过程,一个基础版的音乐播放器完整开发完毕。

发表回复