Microsoft WAV从样本中提取频率

时间:2014-01-06 00:16:43

标签: audio lua wav

好的,所以我正在尝试在Lua中播放WAV文件。就信息而言,我已经说了些什么,但是我还是不得不去播放真正的歌曲了。我正在使用的功能是Speaker.start(频道,频率)。我很想从原始文件中在Lua中做这样的事情,我不知道样本数据代表什么。我的问题是,我如何获得频道和频率播放?它甚至可能吗?

--(( Variables ))--

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

local Speaker = peripheral.wrap("back")

--(( Functions ))--

-- returns a HEX string
local function BigEndian(Size)
    local Str = ""
    for Count = 1,Size do
        Str = Str .. string.char(File.read())
    end
    return Str
end

-- returns a HEX string
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

--(( Main program ))--

-- Variables
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 chunk
ChunkID = BigEndian(4)
ChunkSize = tonumber(LittleEndian(4), 16) + 8
Format = BigEndian(4)

-- Subchunk 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)

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

-- Printing
print("RIFF chunk")
print("- ChunkID: " .. ChunkID)
print("- ChunkSize: " .. ChunkSize)
print("- Format: " .. Format)
print("Subchunk 1")
print("- ID: " .. Subchunk1ID)
print("- Size: " .. Subchunk1Size)
print("- Audio Format: " .. AudioFormat)
print("- NumChannels: " .. NumChannels)
print("- Sample Rate: " .. SampleRate)
print("- Byte Rate: " .. ByteRate)
print("- Block Align: " .. BlockAlign)
print("- BitsPerSample: " .. BitsPerSample)
print("Subchunk 2")
print("- ID: " .. Subchunk2ID)
print("- Size: ".. Subchunk2Size)

local Done = 0

while true do
    Done = Done + 1 --          Left                      Right                           Left                         Right
    --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)

    -- Left channel, Right channel
    if Done == 5000 then break end
end

Speaker.stop(0)


--(( EOF ))--

1 个答案:

答案 0 :(得分:2)

WAV文件存储PCM样本数据,该数据位于时域中。很多时候(CD音频为44,100)样本在该时间点取压力水平,并量化以适合给定的位深度。播放这些样本时,它们会接近原始波形。

PCM Sampling

来自Wikipedia PCM article的图片

您要求的是频域中的示例。这里的样本以更大的间隔(大约相隔5-10ms)拍摄,并包含构成声音的频谱信息。也就是说,你可能有2048个“桶”来测量特定频率下的那段时间的声音量。这是通过对原始时域采样波形执行Fourier transform(通常在计算机上实现为FFT)来衡量的。

基本上,您无法使用当前使用的API播放WAV,因为格式根本不同。