Просмотр исходного кода

fix:wav播放时,单次数据需要4字节对齐,mp3解码有问题导致部分MP3无法播放
update:完善music demo,需要配合0007以上固件使用

alienwalker 4 лет назад
Родитель
Сommit
7e93d0c2c3
2 измененных файлов с 165 добавлено и 127 удалено
  1. 2 127
      demo/multimedia/Air105/main.lua
  2. 163 0
      demo/multimedia/Air105/music_demo.lua

+ 2 - 127
demo/multimedia/Air105/main.lua

@@ -5,133 +5,8 @@ VERSION = "1.0.0"
 
 -- sys库是标配
 _G.sys = require("sys")
-
---[[
-接线要求:
-
-SPI 使用常规4线解法
-Air105开发板         TF模块
-PC9                  CS
-PB12(SPI0_CLK)       CLK
-PB14(SPI0_MISO)      MOSI
-PB15(SPI0_MISO)      MISO
-5V                   VCC
-GND                  GND
-]]
-
-
-audio.on(0, function(id, event_id)
-    if event_id == audio.MORE_DATA then
-        sys.publish("moredata")
-    else
-        sys.publish("playover")
-    end
-end)
-
-sys.taskInit(function()
-    --sys.wait(1000) -- 启动延时
-    local spiId = 0
-    local result = spi.setup(
-        spiId,--串口id
-        255, -- 不使用默认CS脚
-        0,--CPHA
-        0,--CPOL
-        8,--数据宽度
-        400*1000  -- 初始化时使用较低的频率
-    )
-    local TF_CS = pin.PB13
-    gpio.setup(TF_CS, 1)
-    --fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因
-    fatfs.mount("SD", 0, TF_CS, 24000000)
-    local data, err = fatfs.getfree("SD")
-    local buff = zbuff.create(1024)
-    local in_buff = zbuff.create(2 * 1024 + 512)
-    if data then
-        log.info("fatfs", "getfree", json.encode(data))
-        f = io.open("/sd/music/test1.mp3", "rb")
-        if f then
-            log.debug("find mp3")
-            data = f:read(2048)
-            codecr = codec.create(codec.MP3)
-            local result, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed = codec.get_audio_info(codecr, data)
-            if result then
-                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(2048)
-                in_buff:copy(nil, data) 
-                result = codec.get_audio_data(codecr, in_buff, buff)
-                audio.write(0, buff)
-                data = f:read(2048)
-                buff:resize(1024)
-                while data and #data > 0 do
-                    sys.waitUntil("moredata", 2000)
-                    in_buff:copy(nil, data) 
-                    buff:resize(65536)
-                    result = codec.get_audio_data(codecr, in_buff, buff)
-                    audio.write(0, buff)
-                    buff:resize(1024)
-                    data = f:read(2048)
-                end
-                sys.waitUntil("playover", 2000)    
-                codec.release(codecr)
-                audio.stop(0)
-            else
-                log.debug("mp3无法解码")
-            end
-            f:close()
-        end
-        data = nil
-        f = io.open("/sd/music/test.wav", "rb")
-        if f then
-            buff:resize(1024)
-            buff:seek(0, zbuff.SEEK_SET)
-            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)
-                    local _, 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) ~= '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))
-                    ByteRate = SampleRate * BlockAlign
-                    data = f:read(ByteRate)
-                    audio.write(0, data)
-                    data = f:read(ByteRate)
-                    audio.write(0, data)
-                    data = f:read(ByteRate)
-                    while data and #data > 0 do
-                        sys.waitUntil("moredata", 2000)
-                        audio.write(0, data)
-                        data = f:read(ByteRate)
-                    end
-                    sys.waitUntil("playover", 2000)
-                    audio.stop(0)
-                end
-            else
-                log.debug(buff:query(0, 4), buff:query(8, 4))
-            end
-            f:close()
-        end
-    else
-        log.info("fatfs", "err", err)
-    end
-
-
-
-    -- #################################################
-
-end)
-
+require "music_demo"
+sys.taskInit(music_demo_start)
 -- 用户代码已结束---------------------------------------------
 -- 结尾总是这一句
 sys.run()

+ 163 - 0
demo/multimedia/Air105/music_demo.lua

@@ -0,0 +1,163 @@
+--[[
+接线要求:
+
+SPI 使用常规4线解法
+Air105开发板         TF模块
+PC9                  CS
+PB12(SPI0_CLK)       CLK
+PB14(SPI0_MISO)      MOSI
+PB15(SPI0_MISO)      MISO
+5V                   VCC
+GND                  GND
+]]
+
+audio.on(0, function(id, event_id)
+    if event_id == audio.MORE_DATA then
+        sys.publish("moredata")
+    else
+        sys.publish("playover")
+    end
+end)
+-- music文件夾,可以換成你自己的目录,不用加/sd/,demo里固定用TF卡目录,如果要本地目录,自行修改
+local music_dir = "/music/"
+
+function music_demo_start()
+    sys.wait(1000) -- 启动延时
+    local spiId = 0
+    local result = spi.setup(
+        spiId,--串口id
+        255, -- 不使用默认CS脚
+        0,--CPHA
+        0,--CPOL
+        8,--数据宽度
+        400*1000  -- 初始化时使用较低的频率
+    )
+    local TF_CS = pin.PB13
+    gpio.setup(TF_CS, 1)
+    -- fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因
+    fatfs.mount("SD", 0, TF_CS, 12000000)
+    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(8 * 1024 + 512)
+    local play_list = {}
+    if data then
+        log.info("fatfs", "getfree", json.encode(data))
+        local dir_nums, dir_info = fatfs.lsdir(music_dir)
+        for k,v in pairs(dir_info) do
+            log.info(v.size, k)
+            play_list[v.size] = "/sd".. music_dir .. k
+        end
+        while true do
+            for k,v in pairs(play_list) do
+                log.info(v)
+                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)
+                            log.info("jump head", in_buff:query(6, 4, true))
+                            f:seek(SEEK_SET, in_buff:query(6, 4, true))
+
+                        end
+                        in_buff:del()
+                        data = f:read(2048)
+                        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)
+                            while buff:used() == 0 do
+                                log.info("need more data to decode", in_buff:used())
+                                data = f:read(2048)
+                                in_buff:copy(nil, data)
+                                result = codec.get_audio_data(codecr, in_buff, buff)
+                            end
+                            log.debug("start", audio.start(0, AudioFormat, NumChannels, SampleRate, BitsPerSample, is_signed))
+                            audio.write(0, buff)
+                            --local tick1,_ = mcu.tick64()
+                            data = f:read(2048)
+                            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(2048)
+                            while data and #data > 0 and not decode_error do
+                                sys.waitUntil("moredata", 2000)
+                                in_buff:copy(nil, data) 
+                                result = codec.get_audio_data(codecr, in_buff, buff)
+                                while buff:used() == 0 do
+                                    log.info("need more data to decode", in_buff:used())
+                                    data = f:read(2048)
+                                    in_buff:copy(nil, data)
+                                    result = codec.get_audio_data(codecr, in_buff, buff)
+                                end
+                                audio.write(0, buff)
+                                data = f:read(2048)
+                            end
+                            sys.waitUntil("playover", 2000)           
+                            
+                            f:close()
+                            audio.stop(0)
+                        else
+                            log.debug("mp3 decode fail!")
+                            f:close()
+                        end
+                        codec.release(codecr)
+                    end
+                end
+                if v:find(".wav") or v:find(".WAV") then
+                    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: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)
+                                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)
+                                    audio.write(0, data)
+                                    data = f:read(SampleRate)
+                                end
+                                sys.waitUntil("playover", 2000)
+                                audio.stop(0)
+                            end
+                        else
+                            log.debug(buff:query(0, 4), buff:query(8, 4))
+                        end
+                        f:close()
+                    end
+                end
+            end
+        end
+    else
+        log.info("fatfs", "err", err)
+    end
+end