从样本中提取频率的 Microsoft WAV

好的,所以我正在尝试在 Lua 中播放 WAV 文件。我已经了解到了一些信息,但是我卡在了实际播放歌曲上。我正在使用的函数是 Speaker.start(Channel, Frequency)。我从未使用过这样的东西来自一个原始文件中的 Lua,并且我不知道样本数据表示什么。我的问题是,我该如何获取 Channel 和 Frequency 来播放它?这是否有可能?

--(( 变量 ))--

local FileName = "song.wav"
local File = fs.open(FileName, "rb")
local ToHex = "%X"

local Speaker = peripheral.wrap("back")

--(( 函数 ))--

-- 返回十六进制字符串
local function BigEndian(Size)
    local Str = ""
    for Count = 1,Size do
        Str = Str .. string.char(File.read())
    end
    return Str
end

-- 返回十六进制字符串
local function LittleEndian(Size)
    local T = {}
    for Count = 1,Size do
        table.insert(T,ToHex:format(File.read()))
    end
    local Str = ""
    for Count = #T,1,-1 do
        Str = Str .. T[Count]
    end
    return Str
end

--(( 主程序 ))--

-- 变量
local ChunkID = ""
local ChunkSize = 0
local Format = ""
local Subchunk1ID = ""
local Subchunk1Size = 0
local AudioFormat = 0
local NumChannels = 0
local SampleRate = 0
local ByteRate = 0
local BlockAlign = 0
local BitsPerSample = 0
local Subchunk2ID = ""
local Subchunk2Size = 0
local ExtraPeramSize = 0

-- RIFF 块
ChunkID = BigEndian(4)
ChunkSize = tonumber(LittleEndian(4), 16) + 8
Format = BigEndian(4)

-- 子块 1
Subchunk1ID = BigEndian(4)
Subchunk1Size = tonumber(LittleEndian(4), 16)
AudioFormat = tonumber(LittleEndian(2), 16)
NumChannels = tonumber(LittleEndian(2), 16)
SampleRate = tonumber(LittleEndian(4), 16)
ByteRate = tonumber(LittleEndian(4), 16)
BlockAlign = tonumber(LittleEndian(2), 16)
BitsPerSample = tonumber(LittleEndian(2), 16)

ExtraPeramSize = tonumber(LittleEndian(2), 16)

-- 子块 2
Subchunk2ID = BigEndian(4)
Subchunk2Size = tonumber(LittleEndian(4), 16)

-- 打印输出
print("RIFF 块")
print("- ID: " .. ChunkID)
print("- 大小: " .. ChunkSize)
print("- 格式: " .. Format)
print("子块 1")
print("- ID: " .. Subchunk1ID)
print("- 大小: " .. Subchunk1Size)
print("- 音频格式: " .. AudioFormat)
print("- 通道数: " .. NumChannels)
print("- 采样率: " .. SampleRate)
print("- 每秒字节数: " .. ByteRate)
print("- 数据块对齐单元: " .. BlockAlign)
print("- 每个样本位数: " .. BitsPerSample)
print("子块 2")
print("- ID: " .. Subchunk2ID)
print("- 大小: " .. Subchunk2Size)

local Done = 0

while true do
    Done = Done + 1 --          左通道                   右通道                           左通道                          右通道
    --local Sample = {{tonumber(LittleEndian(1),16), tonumber(LittleEndian(1),16)}, {tonumber(LittleEndian(1),16), tonumber(LittleEndian(1),16)}}

    local Left = tonumber(LittleEndian(2),16) - 32768
    local Right = tonumber(LittleEndian(2),16)

    local Average = (Left + Right)/2

    Speaker.start(0,Average)

    sleep(0)

    -- 左通道,右通道
    if Done == 5000 then break end
end

Speaker.stop(0)

--(( 结束 ))--
点赞
用户362536
用户362536

WAV 文件存储 PCM 样本数据,它在时间域中。每秒进行多次取样(CD 音频为 44,100 次),以测量该时点上的压力水平,并将其量化以适应给定的比特深度。当你播放这些样本时,它们会近似于原始波形。

PCM Sampling

图像来自维基百科 PCM 文章

你所要求的是在频率域中取样。这里的样品在更大的间隔(相距约 5-10 毫秒)内取样,并包含组成声音的频谱信息。也就是说,在一段时间内你可以测量到特定频率上的声音量,有可能有 2048 个“盛放”该段时间内特定频率声音的“桶”。这是通过执行原始时间域采样波形的 傅里叶变换(通常在计算机上实现为 FFT)来测量的。

基本上,你现在使用的 API 不能使用你所要求的音频格式 WAV,因为这两种格式有根本性的不同。

2014-01-06 00:22:36