1085|3

81

帖子

0

TA的资源

一粒金砂(中级)

简易MP3播发器 [复制链接]

基于RP2的MP3播发器

MP3在90年代非常流行,准备用RP2做个简易MP3,架构如下所示:

image.png

实物搭建照片

1.jpg  

 

数据操作流程框图如下所示:

image.png

 

播放音乐数据流框图: 

image.png  

 

  通过上述三个框图,不用谢文字就可以明白MP3的操作过程

主要代码如下:



# import math
# import machine,gc
import os
import time
import ufont
from ssd1306 import *

from machine import SoftI2C,SoftSPI,Pin,Timer,RTC         #从machine模块导入I2C、Pin子模块
from ssd1306 import SSD1306_I2C#从ssd1306模块中导入SSD1306_I2C子模块
from sdcard import SDCard

i2c = SoftI2C(sda=Pin(4), scl=Pin(5))   #I2C初始化:sda--22, scl -->23
oled = SSD1306_I2C(128, 64, i2c, addr=0x3c) #OLED显示屏初始化:128*64分辨率,OLED的I2C地址是0x3c

KEY1=Pin(14,Pin.IN,Pin.PULL_UP) #L构建KEY对象
KEY2=Pin(15,Pin.IN,Pin.PULL_UP) #R构建KEY对象
KEY3=Pin(13,Pin.IN,Pin.PULL_UP) #UP构建KEY对象
KEY4=Pin(12,Pin.IN,Pin.PULL_UP) #UP构建KEY对象

spisd = SoftSPI(-1, miso=Pin(11), mosi=Pin(10), sck=Pin(9))
sd = SDCard(spisd, Pin(8))

# print('未挂载SD之前:{}'.format(os.listdir()))

vfs=os.VfsFat(sd)
os.mount(vfs,'/sd')

# print('挂载SD开之后:{}'.format(os.listdir()))

os.chdir('sd')

# print('SD卡中的文件:{}'.format(os.listdir()))

sd_list = os.listdir()
sd_row = 0
sd_data = []
for i in sd_list:
    if(i[-3:] == 'wav'):
        sd_data.append(i)
print(sd_data)    
sd_len = len(sd_data)
print(sd_len)

class KEY_INST:

    def __init__(self,key_pin=[]):
        self.KEY = []
        for i in range(len(key_pin)):
            self.KEY.append(Pin(key_pin[i],Pin.IN,Pin.PULL_UP))

    def scan(self):
        if self.KEY[0].value() == 0:
            time.sleep_ms(10)
            if self.KEY[0].value() == 0:
                print("key1 is press : Left")
                while not self.KEY[0].value():
                    pass
                print("key1 is unpress : Left")
                return 1
        if self.KEY[1].value() == 0:
            time.sleep_ms(10)
            if self.KEY[1].value() == 0:
                print("key2 is press : Right")
                while not self.KEY[1].value():
                    pass
                print("key2 is unpress : Right")
                return 2
        if self.KEY[2].value() == 0:
            time.sleep_ms(10)
            if self.KEY[2].value() == 0:
                print("key3 is press : Up")
                while not self.KEY[2].value():
                    pass
                print("key1 is unpress : Up")
                return 3
        if self.KEY[3].value() == 0:
            time.sleep_ms(10)
            if self.KEY[3].value() == 0:
                print("key4 is press : Down")
                while not self.KEY[3].value():
                    pass
                print("key4 is unpress : Down")
                return 4
        return 0

list_of_menus = [20,30,40,50,60,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70]
list_of_word =["1.AllLight","2.Cyclle","3.Flicker","4.AloneLight","5.Arbitrarily","6.EXT","7.XXX"]

class MENU_SHOW():

    def __init__(self,handle,name,word):
        self.menu_name = name
        self.oled = handle
        self.menus = word
        self.len = len(word)

    def txt(self):#显示框架
        self.oled.text(self.menu_name,50,4)      #写入第1行内容
        self.oled.line(0,15,128,15,1)
        self.oled.line(0,63,128,63,1)
        self.oled.line(0,16,128,16,1)
        self.oled.rect(115,20,7,7,1)
        self.oled.rect(115,30,7,7,1)
        self.oled.rect(115,40,7,7,1)
        self.oled.rect(115,50,7,7,1)
        self.oled.rect(0,0,128,64,1)

    def word_fixed(self,i):
        if self.len <= 5:
            for i in range(self.len):
                self.oled.text(self.menus[i],   4, list_of_menus[i])
        else:
            if i<=4:
                for j in range(5):
                    self.oled.text(self.menus[j],   4, list_of_menus[j])
            else:
                for j in range(self.len):
                    self.oled.text(self.menus[j],   4, list_of_menus[j + 4 -i])
        self.oled.show()

    def word_allo(self,word,j):
        self.oled.fill(0)
        self.txt()
        for i in range(len(word)):
                self.oled.text(word[i],   4, list_of_menus[i])
        self.choose_word(j)
#         self.oled.show()

    def choose_word(self,j):#方框先择
        if j<=4:
            self.oled.fill_rect(115,list_of_menus[j-1],7,7,1)
            self.oled.rect(2,list_of_menus[j-1]-2,124,12,1)
        else:
            self.oled.fill_rect(115,list_of_menus[3],7,7,1)
            self.oled.rect(2,list_of_menus[3]-2,124,12,1)   
        self.oled.show()

    def up_down(self,a):#先择项目
        self.oled.fill(0)
        self.txt()
        self.word_fixed(a)
        self.choose_word(a)

    def ext_show(self,a):#退出显示
        self.word(a)
        self.choose_word(a)

from machine import Pin, SoftSPI
import os
from machine import I2S

font = ufont.BMFont("/sd/unifont-14-12917-16.v3.bmf")

# ======= I2S CONFIGURATION =======
SCK_PIN = 16
WS_PIN = 17
SD_PIN = 18
I2S_ID = 0
BUFFER_LENGTH_IN_BYTES = 40000
# ======= I2S CONFIGURATION =======

# ======= AUDIO CONFIGURATION =======
WAV_SAMPLE_SIZE_IN_BITS = 16
FORMAT = I2S.STEREO
SAMPLE_RATE_IN_HZ = 16000#16000
# ======= AUDIO CONFIGURATION =======

class MP3_INST(KEY_INST):
    def __init__(self,lcd,key=[],sd_data=[]):
        self.audio_out = I2S(
                    I2S_ID,
                    sck=Pin(SCK_PIN),
                    ws=Pin(WS_PIN),
                    sd=Pin(SD_PIN),
                    mode=I2S.TX,
                    bits=WAV_SAMPLE_SIZE_IN_BITS,
                    format=FORMAT,
                    rate=SAMPLE_RATE_IN_HZ,
                    ibuf=BUFFER_LENGTH_IN_BYTES,
                )
        self.display = lcd
        self.switch = False
        self.playt = False
        self.data = sd_data
        self.num = 0
        super().__init__(key)
    
    def cal_time(self,t):
        t = t.split(':')
        min = int(t[0])
        sec = float(t[1])
        # print("{}:{}".format(min, sec))
        return min * 60 + sec

    def unpack_lrc(self,name):
        print(name)
        file = open("/sd/{}.lrc".format(name), "r", encoding="utf-8")
        lrc_list = file.readlines()
        file.close()
        author = lrc_list[0][4:-3] + '-' + lrc_list[1][4:-3]  #
        lrc_time = []
        lrc_word = []
        lrc_dict = {}
        for i in lrc_list[4:]:
            lrc_sub = i.replace("[", "]").strip().split("]")
            for j in range(len(lrc_sub) - 1):
                if lrc_sub[j] and lrc_sub[j].startswith('0'):
                    lrc_dict[lrc_sub[j]] = lrc_sub[-1]
        for key in sorted(lrc_dict.keys()):
            lrc_time.append(self.cal_time(key))
            lrc_word.append(lrc_dict[key])
        return author, lrc_time, lrc_word

    def play(self,i):
        self.num = i
        wav = open("/sd/{}".format(self.data[self.num]), "rb")
        _ = wav.seek(44)
        # wav_samples_mv = memoryview(bytearray(10000))
        wav_samples_mv = memoryview(bytearray(11025))
        print("==========  START PLAYBACK ==========")
        self.playt = True
        self.switch = True
        lrc_num = 0
        try:
            while True:
                key_state = self.scan()
                if key_state == 1:
                    self.num = self.num - 1
                    if self.num <= 0:
                        self.num = 1
                    self.switch = True
                    wav.close()
                elif key_state == 2:
                    self.num = self.num + 1
                    if self.num >= sd_len:
                        self.num = 1  
                    self.switch = True
                    wav.close()
                elif key_state == 3:
                    self.playt = not self.playt
                elif key_state == 4:
                    return True
                
                if self.playt:
                    if self.switch:
                        self.switch = False
                        print(self.data[self.num])
                        wav = open("/sd/{}".format(self.data[self.num]), "rb")
                        # wav = open("/sd/linjj.wav"), "rb")
                        _ = wav.seek(44)
                        author, lrc_time, lrc_word = self.unpack_lrc(self.data[self.num][:-4])
                        print(author)
                        font.text(self.display, author, 0, 8, show=True, clear=True, auto_wrap=False)
                        now = time.time()
                        lrc_num = 0

                    if time.time() - now >= lrc_time[lrc_num]:
                        lrc_num = lrc_num + 1
                        if lrc_num >= len(lrc_time):
                            lrc_num = len(lrc_time) - 1
                        font.text(self.display, author, 0, 8, show=True, clear=True, auto_wrap=False)
                        font.text(self.display, lrc_word[lrc_num], 0, 24, show=True, clear=False, auto_wrap=True)

                    num_read = wav.readinto(wav_samples_mv)
                    if num_read == 0:
                        self.num = self.num + 1
                        if self.num > sd_len-1:
                            self.num = 0
                        wav = open("/sd/{}".format(self.data[self.num]), "rb")
                        _ = wav.seek(44)
                        # print(self.data[self.num])
                        author, lrc_time, lrc_word = self.unpack_lrc(self.data[self.num])
                        font.text(self.display, author, 0, 8, show=True, clear=True, auto_wrap=False)
                    else:
                        _ = self.audio_out.write(wav_samples_mv[:num_read])
        except (KeyboardInterrupt, Exception) as e:
            print("caught exception {} {}".format(type(e).__name__, e))
        # cleanup
        wav.close()

def donghua():
    for i in range(2,269):
        file = open("/sd/text_img_{}.dat".format(i), "rb")
        buffer = file.read(128*8)
        file.close()
        fb_buffer = framebuf.FrameBuffer(bytearray(buffer), 128, 64, framebuf.MONO_HMSB)

        oled.blit(fb_buffer, 0, 0)
        oled.show()

if __name__ == "__main__":
    menu_show = MENU_SHOW(oled,"SD",sd_data[0:4])
    key_press = KEY_INST([14,15,13,12])
    menu_num = 1
    donghua()
    menu_show.word_allo(sd_data[0:4],1)
    while True:
        key_state = key_press.scan()
        if key_state == 1:
            menu_num = menu_num - 1
            if menu_num <= 0:
                menu_num = 1
            if menu_num > 4:
                menu_show.word_allo(sd_data[menu_num-4:menu_num],menu_num)
            else:
                menu_show.word_allo(sd_data[0:4],menu_num)
        elif key_state == 2:
            menu_num = menu_num + 1
            if menu_num > sd_len:
                menu_num = 1
            if menu_num > 4:
                menu_show.word_allo(sd_data[menu_num-4:menu_num],menu_num)
            else:
                menu_show.word_allo(sd_data[0:4],menu_num)
        elif key_state == 3:
            pass
            #进入下一级目录,
            print(sd_data[menu_num - 1])
            audio_wav = MP3_INST(oled,[14,15,13,12],sd_data)
            audio_wav.play(menu_num - 1)
            # menu_show.choose_word(1)
        elif key_state == 4:
            #返回上一级目录
            menu_show.word_allo(sd_data[0:4],1)
            





            







 

MP3功能演示操作:链接如下所示:

https://training.eeworld.com.cn/uploadcourse/68027/lesson

 

MP3

 

源码如下:

MP3.rar (17.37 MB, 下载次数: 0)

最新回复

明白了。   详情 回复 发表于 2023-7-18 16:41

回复
举报

3251

帖子

0

TA的资源

五彩晶圆(中级)

不错,RP2是什么???

点评

Raspberry Pi Pico W简写RPP,缩写RP2  详情 回复 发表于 2023-7-18 15:16

回复

81

帖子

0

TA的资源

一粒金砂(中级)

tagetage 发表于 2023-7-17 09:20 不错,RP2是什么???

Raspberry Pi Pico W简写RPP,缩写RP2

点评

明白了。  详情 回复 发表于 2023-7-18 16:41

回复

3251

帖子

0

TA的资源

五彩晶圆(中级)

冒险武者 发表于 2023-7-18 15:16 Raspberry Pi Pico W简写RPP,缩写RP2

明白了。


回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表