瀏覽代碼

update:用按键控制歌曲播放

alienwalker 3 年之前
父節點
當前提交
7ecb99b75e
共有 2 個文件被更改,包括 238 次插入125 次删除
  1. 6 3
      demo/multimedia/Air105/main.lua
  2. 232 122
      demo/multimedia/Air105/music_demo.lua

+ 6 - 3
demo/multimedia/Air105/main.lua

@@ -1,12 +1,15 @@
 
 -- LuaTools需要PROJECT和VERSION这两个信息
-PROJECT = "test"
-VERSION = "1.0.0"
+PROJECT = "test_audio"
+VERSION = "2.0.0"
 
 -- sys库是标配
 _G.sys = require("sys")
+_G.sysplus = require("sysplus")
+
+log.style(1)
 require "music_demo"
-sys.taskInit(music_demo_start)
+
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()

+ 232 - 122
demo/multimedia/Air105/music_demo.lua

@@ -1,3 +1,6 @@
+--用2*2行列键盘实现切换歌曲,选择上一首,选择下一首,暂停/恢复
+--用软件行列键盘,底层已经做好防抖了,如果用单独按键,自行处理
+--当前选择上/下一首不会立刻生效,按切换歌曲才会生效,如果需要立刻生效,就取消相应注释即可
 --[[
 接线要求:
 
@@ -10,22 +13,92 @@ PB15(SPI0_MISO)      MISO
 5V                   VCC
 GND                  GND
 ]]
+-- music文件夾,可以換成你自己的目录,不用加/sd/,demo里固定用TF卡目录,如果要本地目录,自行修改
+local musicDir = "/music/"
+local taskName = "task_audio"
+
+local playList = {}
+local curPlay = 0
+local prePlay = 0
+local nextPlay = 1
+local tFiles = 0
+local isPause = false
+local MSG_MD = "moreData"   -- 播放缓存有空余
+local MSG_PD = "playDone"   -- 播放完成所有数据
+local MSG_NEW = "audioNew"  -- 播放新的歌曲
 
-audio.on(0, function(id, event_id)
-    if event_id == audio.MORE_DATA then
-        sys.publish("moredata")
+audio.on(0, function(id, event)
+    if event == audio.MORE_DATA then
+        sysplus.sendMsg(taskName, MSG_MD)
     else
-        sys.publish("playover")
+        sysplus.sendMsg(taskName, MSG_PD)
     end
 end)
--- music文件夾,可以換成你自己的目录,不用加/sd/,demo里固定用TF卡目录,如果要本地目录,自行修改
-local music_dir = "/music/"
 
-function music_demo_start()
-    sys.wait(100) -- 启动延时
-    local tag_len = 0
-    local frame_len = 1152 * 4
-    local spiId = 0
+local function moveNext()
+    prePlay = curPlay
+    curPlay = curPlay + 1
+    if curPlay >= tFiles then
+        curPlay = 0
+    end
+    nextPlay = curPlay + 1
+    if nextPlay >= tFiles then
+        nextPlay = 0
+    end
+    log.info("选择下一首")
+    log.info("上一首", prePlay, playList[prePlay])
+    log.info("选择", curPlay, playList[curPlay])
+    log.info("下一首", nextPlay, playList[nextPlay])
+end
+
+local function movePre()
+    nextPlay = curPlay
+    curPlay = prePlay
+    if prePlay > 0 then
+        prePlay = prePlay - 1
+    else
+        prePlay = tFiles - 1
+    end
+    log.info("选择上一首")
+    log.info("上一首", prePlay, playList[prePlay])
+    log.info("选择", curPlay, playList[curPlay])
+    log.info("下一首", nextPlay, playList[nextPlay])
+end
+
+local function task_cb(msg)
+    log.info(msg[1], msg[2], msg[3], msg[4])
+end
+
+-- 用软件行列键盘,底层已经做好防抖了,如果用单独按键,自行处理
+sys.subscribe("SOFT_KB_INC", function(port, data, state)
+    -- log.info(data, state)
+    -- 按下起效
+    if state > 0 then
+        if data == 0 then
+            -- 开始播放或者立刻结束当前歌曲并播放下一首
+            sysplus.sendMsg(taskName, MSG_NEW)
+        elseif data == 1 then
+            movePre()
+            -- 如果需要立刻就切换歌曲就取消注释
+            -- sysplus.sendMsg(taskName, MSG_NEW)
+        elseif data == 16 then
+            moveNext()
+            -- 如果需要立刻就切换歌曲就取消注释
+            -- sysplus.sendMsg(taskName, MSG_NEW)
+        elseif data == 17 then
+            isPause = not isPause
+            audio.pause(0, isPause)
+            log.info("暂停状态", isPause)
+        end
+    end
+end)
+
+local function audio_task()
+    softkb.init(0, {pin.PD12, pin.PD13}, {pin.PE1, pin.PE2})
+    local tagLen = 0
+    local frameLen = 1152 * 4
+    local spiId = 2
+    local nowPlay
     local result = spi.setup(
         spiId,--串口id
         255, -- 不使用默认CS脚
@@ -34,141 +107,178 @@ function music_demo_start()
         8,--数据宽度
         400*1000  -- 初始化时使用较低的频率
     )
-    local TF_CS = pin.PB13
+    local isMP3 = false
+    local TF_CS = pin.PB3
     gpio.setup(TF_CS, 1)
     -- fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因
-    fatfs.mount("SD", 0, TF_CS, 24000000)
+    fatfs.mount("SD", spiId, TF_CS, 24000000)
     -- fatfs.mount("SD", 0, TF_CS, 24000000)
     local data, err = fatfs.getfree("SD")
-    -- usbapp.udisk_attach_sdhc(0)
-    -- usbapp.start(0)
-    -- sys.wait(600000)
     local buff = zbuff.create(1024)
-    local in_buff = zbuff.create(frame_len * 3 + 512)
-    local play_list = {}
+    local in_buff = zbuff.create(frameLen * 3 + 512)
+    local isRun = false
+    local result, AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, BitsPerSample, is_signed
+
     if data then
         log.info("fatfs", "getfree", json.encode(data))
-        local dir_nums, dir_info = fatfs.lsdir(music_dir)
+        local dir_nums, dir_info = fatfs.lsdir(musicDir)
         for k,v in pairs(dir_info) do
-            log.info("find",k)
-            play_list[v.size] = "/sd".. music_dir .. k
+            if k:find(".mp3") or k:find(".MP3") or k:find(".wav") or k:find(".WAV") then
+                log.info("找到",k)
+                playList[tFiles] = k
+                tFiles = tFiles + 1
+            end
         end
+        log.info("总共", tFiles)
+        prePlay = tFiles - 1
+        log.info("等待切换歌曲")
+        sysplus.waitMsg(taskName, MSG_NEW)
         while true do
-            for k,v in pairs(play_list) do
-                log.info('play',v)
-                log.info(rtos.meminfo("sys"))
-                log.info(rtos.meminfo("lua"))
-                if v:find(".mp3") or v:find(".MP3") then
-                    f = io.open(v, "rb")               
-                    if f then
-                        -- log.debug("find mp3")
-                        in_buff:del()
-                        data = f:read(10)
-                        if data:sub(1, 3) == 'ID3' then
-                            in_buff:copy(nil, data)
-                            tag_len = ((in_buff:query(6, 1, true) & 0x7f) << 21) + ((in_buff:query(7, 1, true) & 0x7f) << 14) + ((in_buff:query(8, 1, true) & 0x7f) << 7) + (in_buff:query(9, 1, true) & 0x7f)
-                            log.info("jump head",  tag_len)
-                            f:seek(SEEK_SET, tag_len)
-                        end
-                        in_buff:del()
-                        data = f:read(frame_len)
-                        codecr = codec.create(codec.MP3)
-                        local result, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed = codec.get_audio_info(codecr, data)
-                        if result then
-                            log.info("mp3 info", NumChannels, SampleRate, BitsPerSample)
-                            buff:resize(65536)
-                            in_buff:copy(nil, data)
-                            result = codec.get_audio_data(codecr, in_buff, buff)
-                            log.debug("start", audio.start(0, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed))
-                            audio.write(0, buff)
-                            --local tick1,_ = mcu.tick64()
-                            data = f:read(frame_len)
-                            in_buff:copy(nil, data) 
-                            result = codec.get_audio_data(codecr, in_buff, buff)
-                            --local tick2,_ = mcu.tick64()
-                            --log.debug(mcu.dtick64(tick2, tick1)/_)
-                            audio.write(0, buff)
-                            data = f:read(frame_len)
-                            while result do
-                                sys.waitUntil("moredata", 2000)
-                                if in_buff:used() >= frame_len * 2 then
-                                    log.info("no need new data", in_buff:used())
-                                    result = codec.get_audio_data(codecr, in_buff, buff)
-                                    audio.write(0, buff)
-                                else
-                                    data = f:read(frame_len)
-                                    in_buff:copy(nil, data) 
-                                    if #data ~= frame_len then
-                                        result = codec.get_audio_data(codecr, in_buff, buff, false)
-                                        log.info("解码结束")
-                                        result = false
-                                    else
-                                        result = codec.get_audio_data(codecr, in_buff, buff)
-                                    end
-                                    audio.write(0, buff)
-                                end
-
-                            end
-                            sys.waitUntil("playover", 2000)           
-                            
-                            f:close()
-                            audio.stop(0)
-                        else
-                            log.debug("mp3 decode fail!")
-                            f:close()
-                        end
-                        codec.release(codecr)
+            isRun = false
+            isMP3 = false
+            nowPlay = curPlay
+            log.info("开始播放")
+            log.info("上一首", prePlay, playList[prePlay])
+            log.info("当前", curPlay, playList[curPlay])
+            log.info("下一首", nextPlay, playList[nextPlay])
+            f = io.open("/sd".. musicDir .. playList[curPlay], "rb")
+            if f then
+                if playList[curPlay]:find(".mp3") or playList[curPlay]:find(".MP3") then
+                    -- 解析MP3的必要信息
+                    isMP3 = true
+                    in_buff:del()
+                    data = f:read(10)
+                    if data:sub(1, 3) == 'ID3' then
+                        in_buff:copy(nil, data)
+                        tagLen = ((in_buff:query(6, 1, true) & 0x7f) << 21) + ((in_buff:query(7, 1, true) & 0x7f) << 14) + ((in_buff:query(8, 1, true) & 0x7f) << 7) + (in_buff:query(9, 1, true) & 0x7f)
+                        log.info("jump head",  tagLen)
+                        f:seek(SEEK_SET, tagLen)
                     end
-                end
-                if v:find(".wav") or v:find(".WAV") then
+                    in_buff:del()
+                    data = f:read(frameLen)
+                    codecr = codec.create(codec.MP3)
+                    result, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed = codec.get_audio_info(codecr, data)
+                    if result then
+                        log.info("mp3 info", NumChannels, SampleRate, BitsPerSample)
+                        buff:resize(65536)
+                        in_buff:copy(nil, data)
+                        result = codec.get_audio_data(codecr, in_buff, buff)
+                        log.debug("start", audio.start(0, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed))
+                        audio.write(0, buff)
+                        data = f:read(frameLen)
+                        in_buff:copy(nil, data) 
+                        result = codec.get_audio_data(codecr, in_buff, buff)
+                        audio.write(0, buff)
+                        data = f:read(frameLen)
+                        isRun = true        
+                    else
+                        log.debug("mp3解码失败!")
+                    end
+                else
+                    isMP3 = false
                     data = nil
-                    f = io.open(v, "rb")
-                    if f then
-                        buff:del()
-                        buff:copy(0, f:read(12))
-                        if buff:query(0, 4) == 'RIFF' and buff:query(8, 4) == 'WAVE' then             
-                            local total = buff:query(4, 4, false)
+                    buff:del()
+                    -- 解析WAV的必要信息
+                    buff:copy(0, f:read(12))
+                    if buff:query(0, 4) == 'RIFF' and buff:query(8, 4) == 'WAVE' then             
+                        local total = buff:query(4, 4, false)
+                        buff:copy(0, f:read(8))
+                        if buff:query(0, 4) == 'fmt ' then      
+                            buff:copy(0, f:read(16))
+                            buff:seek(0, zbuff.SEEK_SET)
+                            result, AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, BitsPerSample = buff:unpack("<HHIIHH")
+                            log.debug("find fmt info", AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, BitsPerSample)
                             buff:copy(0, f:read(8))
-                            if buff:query(0, 4) == 'fmt ' then      
-                                buff:copy(0, f:read(16))
-                                buff:seek(0, zbuff.SEEK_SET)
-                                local _, AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, BitsPerSample = buff:unpack("<HHIIHH")
-                                log.debug("find fmt info", AudioFormat, NumChannels, SampleRate, ByteRate, BlockAlign, BitsPerSample)
+                            if buff:query(0, 4) ~= 'data' then
+                                buff:copy(0, buff:query(4, 4, false))
                                 buff:copy(0, f:read(8))
-                                if buff:query(0, 4) ~= 'data' then
-                                    buff:copy(0, buff:query(4, 4, false))
-                                    buff:copy(0, f:read(8))
-                                end
-                                log.debug("start", audio.start(0, AudioFormat, NumChannels, SampleRate, BitsPerSample))
-                                SampleRate = (SampleRate * BlockAlign // 8) & ~(3)
-                                log.info("size", SampleRate)
-                                data = f:read(SampleRate)
-                                audio.write(0, data)
-                                data = f:read(SampleRate)
-                                audio.write(0, data)
-                                data = f:read(SampleRate)
-                                while data and #data > 0 do
-                                    sys.waitUntil("moredata", 2000)
+                            end
+                            log.debug("start", audio.start(0, AudioFormat, NumChannels, SampleRate, BitsPerSample))
+                            SampleRate = (SampleRate * BlockAlign // 8) & ~(3)
+                            log.info("size", SampleRate)
+                            data = f:read(SampleRate)
+                            audio.write(0, data)
+                            data = f:read(SampleRate)
+                            audio.write(0, data)
+                            data = f:read(SampleRate)
+                            isRun = true
+                        end
+                    else
+                        log.debug("不正确的RIFF头", buff:query(0, 4), buff:query(8, 4))
+                    end
+
+                end
+                if isRun then
+                    while true do
+                        local msg = sysplus.waitMsg(taskName, nil, 2000)
+                        if type(msg) == 'table' then
+                            if msg[1] == MSG_MD and isRun then
+                                if isMP3 then
+                                    if in_buff:used() >= frameLen * 2 then
+                                        isRun = codec.get_audio_data(codecr, in_buff, buff)
+                                        audio.write(0, buff)
+                                    else
+                                        data = f:read(frameLen)
+                                        in_buff:copy(nil, data) 
+                                        if #data ~= frameLen then
+                                            isRun = codec.get_audio_data(codecr, in_buff, buff, false)
+                                            log.info("解码结束")
+                                            isRun = false
+                                        else
+                                            isRun = codec.get_audio_data(codecr, in_buff, buff)
+                                        end
+                                        audio.write(0, buff)
+                                    end
+                                else
                                     audio.write(0, data)
                                     data = f:read(SampleRate)
+                                    if not data or #data == 0 then
+                                        log.info("没有数据了")
+                                        isRun = false
+                                    end
                                 end
-                                sys.waitUntil("playover", 2000)
-                                audio.stop(0)
+                            elseif msg[1] == MSG_PD then
+                                log.info("播放结束")
+                                break
+                            elseif msg[1] == MSG_NEW then
+                                log.info("切换歌曲")
+                                break
                             end
                         else
-                            log.debug(buff:query(0, 4), buff:query(8, 4))
+                            if not isPause then
+                                log.error(type(msg), msg)
+                            end
                         end
-                        f:close()
                     end
                 end
-                log.info(rtos.meminfo("sys"))
-                log.info(rtos.meminfo("lua"))
+                if isMP3 then
+                    codec.release(codecr)
+                end
+                audio.stop(0)
+                f:close()
+            end
+            -- 如果有底层的播放消息,也释放掉
+            sysplus.waitMsg(taskName, MSG_MD, 10)
+            sysplus.waitMsg(taskName, MSG_PD, 10)
+            isPause = false
+            log.info(rtos.meminfo("sys"))
+            log.info(rtos.meminfo("lua"))
+            if nowPlay == curPlay then
+                prePlay = curPlay
+                curPlay = curPlay + 1
+                if curPlay >= tFiles then
+                    curPlay = 0
+                end
+                nextPlay = curPlay + 1
+                if nextPlay >= tFiles then
+                    nextPlay = 0
+                end
             end
         end
-
-
-
     else
         log.info("fatfs", "err", err)
     end
-end
+    sysplus.taskDel(taskName)
+end
+
+sysplus.taskInitEx(audio_task, taskName, task_cb)