1
votes

Okay, so I'm trying to play a WAV file in Lua. I've gotton as far as the information, but I'm getting stuck on playing the actual song. The function I'm using is Speaker.start(Channel, Frequency). I'm new to doing anything like this in Lua from a raw file, and I don't know what the sample data represents. My question is, how would I get the Channel and Frequency to play it? Is it even possible?

--(( 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
I'm not a Lua programmer, but it sounds like the api you are using is designed to generate tones, not reproduce audio. I think you need a different API.Bjorn Roche
What library are you using?Oliver

1 Answers

2
votes

WAV files store PCM sample data, which is in the time domain. Many times a second (44,100 for CD audio) a sample is take of the pressure level at that point in time, and quantised to fit a given bit depth. When you play back these samples, they approximate the original waveform.

PCM Sampling

Image from Wikipedia PCM article

What you are asking for is a sample in the frequency domain. Samples here are taken at much larger intervals (around 5-10ms apart) and contain the spectrum information that makes up the sound. That is, you may have 2048 "buckets" measuring the amount of sound at a particular frequency for that chunk of time. This is measured by doing a Fourier transform (commonly implemented as FFT on computers) of the original time domain sampled waveform.

Basically, you can't playback WAVs using the API you are using now, as the format is fundamentally different.