Microsoft WAV extracting frequency from sample - audio

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

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.
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.

Related

Package functions on strings using GPU in Python - Generating addresses from private keys

Problem: I am trying to convert a very big list (many millions) of private keys (hexadecimal format, stored in a list of strings) to addresses. Can this be run on the GPU?
I have tried looking for resources on how to adapt my code to a GPU/CUDA-friendly version. However, I've found that most examples online are for pure math operations on a list of ints or floats. Also, the function where the 'processing' is defined is also entirely re-written, and does not use functions from packages (other than those already supported by numpy etc.).
Is there a way to make the [private key -> public key -> address] process GPU-friendly, and can string operations be carried out on a GPU in the first place?
The following is what I have for my serial CPU version for Python3.x:
import codecs
import hashlib
import ecdsa
def get_pub_keys(priv_key):
private_hex = codecs.decode(priv_key, 'hex')
key = ecdsa.SigningKey.from_string(private_hex, curve=ecdsa.SECP256k1).verifying_key
key_bytes = key.to_string()
key_hex = codecs.encode(key_bytes, 'hex')
public_key_uncompressed = b'04' + key_hex
key_string = key_hex.decode('utf-8')
last_byte = int(key_string[-1], 16)
half_len = len(key_hex) // 2
key_half = key_hex[:half_len]
bitcoin_byte = b'02' if last_byte % 2 == 0 else b'03'
public_key_compressed = bitcoin_byte + key_half
return public_key_uncompressed, public_key_compressed
def public_to_address(public_key):
public_key_bytes = codecs.decode(public_key, 'hex')
# Run SHA256 for the public key
sha256_bpk = hashlib.sha256(public_key_bytes)
sha256_bpk_digest = sha256_bpk.digest()
# Run ripemd160 for the SHA256
ripemd160_bpk = hashlib.new('ripemd160')
ripemd160_bpk.update(sha256_bpk_digest)
ripemd160_bpk_digest = ripemd160_bpk.digest()
ripemd160_bpk_hex = codecs.encode(ripemd160_bpk_digest, 'hex')
# Add network byte
network_byte = b'00'
network_bitcoin_public_key = network_byte + ripemd160_bpk_hex
network_bitcoin_public_key_bytes = codecs.decode(network_bitcoin_public_key, 'hex')
# Double SHA256 to get checksum
sha256_nbpk = hashlib.sha256(network_bitcoin_public_key_bytes)
sha256_nbpk_digest = sha256_nbpk.digest()
sha256_2_nbpk = hashlib.sha256(sha256_nbpk_digest)
sha256_2_nbpk_digest = sha256_2_nbpk.digest()
sha256_2_hex = codecs.encode(sha256_2_nbpk_digest, 'hex')
checksum = sha256_2_hex[:8]
# Concatenate public key and checksum to get the address
address_hex = (network_bitcoin_public_key + checksum).decode('utf-8')
wallet = base58(address_hex)
return wallet
def base58(address_hex):
alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
b58_string = ''
# Get the number of leading zeros and convert hex to decimal
leading_zeros = len(address_hex) - len(address_hex.lstrip('0'))
# Convert hex to decimal
address_int = int(address_hex, 16)
# Append digits to the start of string
while address_int > 0:
digit = address_int % 58
digit_char = alphabet[digit]
b58_string = digit_char + b58_string
address_int //= 58
# Add '1' for each 2 leading zeros
ones = leading_zeros // 2
for one in range(ones):
b58_string = '1' + b58_string
return b58_string
def get_addresses(i):
key1,key2 = get_pub_keys(i)
add1 = public_to_address(key1)
add2 = public_to_address(key2)
return add1, add2
filename = 'bunchOfHexKeys.txt'
with open(filename, 'r') as f:
hexKeys = f.read().splitlines()
addresses = []
for i in hexKeys:
addresses.append(get_addresses(i))
As can be seen, I'm using many functions from the 3 imported packages. So far the only way I can see is to rewrite those. Is there another way?
The size of hexKeys isn't an issue for the GPU cache size, as I can just adjust the input list as needed.

Split string into cell array by positions

I have a file with strings of a known length, but no separator.
% What should be the result
vals = arrayfun(#(x) ['Foobar ', num2str(x)], 1:100000, 'UniformOutput', false);
% what the file looks like when read in
strs = cell2mat(vals);
strlens = cellfun(#length, vals);
The most straightforward approach is quite slow:
out = cell(1, length(strlens));
for i=1:length(strlens)
out{i} = fread(f, strlens(i), '*char');
end % 5.7s
Reading everything in and splitting it up afterwards is a lot faster:
strs = fread(f, sum(strlens), '*char');
out = cell(1, length(strlens));
slices = [0, cumsum(strlens)];
for i=1:length(strlens)
out{i} = strs(slices(i)+1:slices(i+1));
end % 1.6s
With a mex function I can get down to 0.6s, so there's still a lot of room for improvement. Can I get comparable performance with pure Matlab (R2016a)?
Edit: the seemingly perfect mat2cell function doesn't help:
out = mat2cell(strs, 1, strlens); % 2.49s
Your last approach – reading everything at once and splitting it up afterwards – looks pretty optimal to me, and is how I do stuff like this.
For me, it's running in about 80 ms seconds when the file is on a local SSD in both R2016b and R2019a, on Mac.
function out = scratch_split_strings(strlens)
%
% Example:
% in_strs = arrayfun(#(x) ['Foobar ', num2str(x)], 1:100000, 'UniformOutput', false);
% strlens = cellfun(#length, in_strs);
% big_str = cat(2, in_strs{:});
% fid = fopen('text.txt'); fprintf(fid, '%s', big_str); fclose(fid);
% scratch_split_strings(strlens);
t0 = tic;
fid = fopen('text.txt');
txt = fread(fid, sum(strlens), '*char');
fclose(fid);
fprintf('Read time: %0.3f s\n', toc(t0));
str = txt;
t0 = tic;
out = cell(1, length(strlens));
slices = [0, cumsum(strlens)];
for i = 1:length(strlens)
out{i} = str(slices(i)+1:slices(i+1))';
end
fprintf('Munge time: %0.3f s\n', toc(t0));
end
>> scratch_split_strings(strlens);
Read time: 0.002 s
Munge time: 0.075 s
Have you stuck it in the profiler to see what's taking up your time here?
As far as I know, there is no faster way to split up a single primitive array into variable-length subarrays with native M-code. You're doing it right.

Subfunctions in matlab

I have function called Assignment in Matlab with PsychToolBox. This function shows a random color to the paritcipant and require participant to name the color and record this data.
function should return me 2 output as a string
rgb code of the random color like: trial(1).color = [5 5 5]
a matrix which correspond to the sound record.
I write the main functions and color part is okay, but I cannot integrate the recording function into the main function.
in main function I use this string trial.data = recording(1,0,5)
and then I wrote a subfunction named "recording"
function recording (wavfilename, voicetrigger, maxsecs)
bla, bla
end
However, the main function does not recognize the subfunction. Am I doing an logical error? the error message is below
Error: File: assignment.m Line: 40 Column: 27
Unexpected MATLAB expression.
line 40 = trial.data = recording(1,0,5)
function ass8(trial)
Screen('Preference', 'SkipSyncTests', 1)
ListenChar(2);
Screen('HideCursorHelper', 0, 0)
[myWin, rect]=Screen('OpenWindow',0,[128,128,128]);
centerX=rect(3)/2;
centerY=rect(4)/2;
for trial = 1:100
Screen('TextSize', myWin, 30);
Screen('TextFont', myWin, 'Times');
[normBoundsRect, offsetBoundsRect] = Screen('TextBounds',myWin, 'What is the color of the rectangle?');
Screen('DrawText', myWin, 'What is the color of the rectangle?', (centerX-(normBoundsRect(3)/2)),(centerY-(normBoundsRect(4)/2+150)), [0,0,0]);
Screen('Flip', myWin)
WaitSecs(1)% inter stimulus interval
color = randi(255,1,3)
while 1
Screen('FillRect', myWin, color ,[583, 284, 783, 484])
% [ (centerX-100), (centerY-100), (centerX+100),(centerY+100)]);
Screen('Flip', myWin)
WaitSecs(3)
trial.color = color % trial 'ın rengini belirtmesini söyledim
trial.data = reco(1,0 5)% trial'ın ismi 1, kayıt yapacağı süre ise 3 sn
if Waitsecs(3)==1
break; % Terminates the loop if the condition is % satisfied
end
end
pause(.05);
% [clicks, x, y, buttons] = GetClicks(myWin);
%
% buttons=0;
% while ~buttons
% [x, y, buttons] = GetMouse(myWin);
% end
% while 1
% [x,y,buttons] = GetMouse(myWin);
% if ~buttons(1)
% break;
% end
% end
Screen('CloseAll')
end
end
function reco(wavfilename, voicetrigger, maxsecs)
%
% AssertOpenGL;
if nargin < 1
wavfilename = [];
end
if nargin < 2
voicetrigger = [];
end
if isempty(voicetrigger)
voicetrigger = 0;
end
if nargin < 3
maxsecs = [];
end
if isempty(maxsecs)
maxsecs = inf;
end
InitializePsychSound;
freq = 44100;
pahandle = PsychPortAudio('Open', [], 2, 0, freq, 2);
PsychPortAudio('GetAudioData', pahandle, 10);
PsychPortAudio('Start', pahandle, 0, 0, 1);
if voicetrigger > 0
% Yes. Fetch audio data and check against threshold:
level = 0;
% Repeat as long as below trigger-threshold:
while level < voicetrigger
% Fetch current audiodata:
[audiodata offset overflow tCaptureStart] = PsychPortAudio('GetAudioData', pahandle);
% Compute maximum signal amplitude in this chunk of data:
if ~isempty(audiodata)
level = max(abs(audiodata(1,:)));
else
level = 0;
end
% Below trigger-threshold?
if level < voicetrigger
% Wait for a millisecond before next scan:
WaitSecs(0.0001);
end
end
else
% Start with empty sound vector:
recordedaudio = [];
end
s = PsychPortAudio('GetStatus', pahandle)
while ~KbCheck && ((length(recordedaudio) / s.SampleRate) < maxsecs)
% Wait a second...
WaitSecs(1);
% Query current capture status and print it to the Matlab window:
s = PsychPortAudio('GetStatus', pahandle);
% Print it:
fprintf('\n\nAudio capture started, press any key for about 1 second to quit.\n');
fprintf('This is some status output of PsychPortAudio:\n');
disp(s);
% Retrieve pending audio data from the drivers internal ringbuffer:
audiodata = PsychPortAudio('GetAudioData', pahandle);
nrsamples = size(audiodata, 2);
% Plot it, just for the fun of it:
plot(1:nrsamples, audiodata(1,:), 'r', 1:nrsamples, audiodata(2,:), 'b');
drawnow;
% And attach it to our full sound vector:
recordedaudio = [recordedaudio audiodata]; %#ok<AGROW>
end
PsychPortAudio('Stop', pahandle);
audiodata = PsychPortAudio('GetAudioData', pahandle);
recordedaudio = [recordedaudio audiodata];
PsychPortAudio('Close', pahandle);
if ~isempty(wavfilename)
psychwavwrite(transpose(recordedaudio), 44100, 16, wavfilename)
end
fprintf('helal lan!\n');
ListenChar(2);
end

How to read a C generated binary file in Lua

I want to read a 32 bit integer binary file provided by another program. The file contains only integer and no other characters (like spaces or commas). The C code to read this file is as follows:
FILE* pf = fopen("C:/rktemp/filename.dat", "r");
int sz = width*height;
int* vals = new int[sz];
int elread = fread((char*)vals, sizeof(int), sz, pf);
for( int j = 0; j < height; j++ )
{
for( int k = 0; k < width; k++ )
{
int i = j*width+k;
labels[i] = vals[i];
}
}
delete [] vals;
fclose(pf);
But I don't know how to read this file into array using Lua.
I've tried to read this file using io.read, but part of the array looks like this:
~~~~~~xxxxxxxxyyyyyyyyyyyyyyzzzzzzzz{{{{{{{{{|||||||||}}}}}}}}}}}~~~~~~~~~xxxxxxxyyyyyyyyyyyyyyzzzzzz{{{{{{{{{{|||||||||}}}}}}}}}}}~~~~~~~~~xxyyyyyyyyyyyyyzzzzz{{{{{{|||}}}yyyyyyyyyyyz{{{yyyyyyyyÞľūơǿȵɶʢ˺̤̼ͽаҩӱľǿجٴȵɶʢܷݸ˺໻⼼ӱľǿ
Also the Matlab code to read this file is like this:
row = image_size(1);
colomn = image_size(2);
fid = fopen(data_path,'r');
A = fread(fid, row * colomn, 'uint32')';
A = A + 1;
B = reshape(A,[colomn, row]);
B = B';
fclose(fid);
I've tried a function to convert bytes to integer, my code is like this:
function bytes_to_int(b1, b2, b3, b4)
if not b4 then error("need four bytes to convert to int",2) end
local n = b1 + b2*256 + b3*65536 + b4*16777216
n = (n > 2147483647) and (n - 4294967296) or n
return n
end
local sup_filename = '1.dat'
fid = io.open(sup_filename, "r")
st = bytes_to_int(fid:read("*all"):byte(1,4))
print(st)
fid:close()
But it still not read this file properly.
You are only calling bytes_to_int once. You need to call it for every int you want to read. e.g.
fid = io.open(sup_filename, "rb")
while true do
local bytes = fid:read(4)
if bytes == nil then break end -- EOF
local st = bytes_to_int(bytes:byte(1,4))
print(st)
end
fid:close()
Now you can use the new feature of Lua language by calling string.unpack , which has many conversion options for format string. Following options may be useful:
< sets little endian
> sets big endian
= sets native endian
i[n] a signed int with n bytes (default is native size)
I[n] an unsigned int with n bytes (default is native size)
The arch of your PC is unknown, so I assume the data to read is unsigned and native-endian.
Since you are reading binary data from the file, you should use io.open(sup_filename, "rb").
The following code may be useful:
local fid = io.open(sup_filename, "rb")
local contents = fid:read("a")
local now
while not now or now < #contents do
local n, now = string.unpack("=I4", contents, now)
print(n)
end
fid:close()
see also: Lua 5.4 manual

What exactly does a Sample Rate of 44100 sample?

I'm using FMOD library to extract PCM from an MP3. I get the whole 2 channel - 16 bit thing, and I also get that a sample rate of 44100hz is 44,100 samples of "sound" in 1 second. What I don't get is, what exactly does the 16 bit value represent. I know how to plot coordinates on an xy axis, but what am I plotting? The y axis represents time, the x axis represents what? Sound level? Is that the same as amplitude? How do I determine the different sounds that compose this value. I mean, how do I get a spectrum from a 16 bit number.
This may be a separate question, but it's actually what I really need answered: How do I get the amplitude at every 25 milliseconds? Do I take 44,100 values, divide by 40 (40 * 0.025 seconds = 1 sec) ? That gives 1102.5 samples; so would I feed 1102 values into a blackbox that gives me the amplitude for that moment in time?
Edited original post to add code I plan to test soon: (note, I changed the frame rate from 25 ms to 40 ms)
// 44100 / 25 frames = 1764 samples per frame -> 1764 * 2 channels * 2 bytes [16 bit sample] = 7056 bytes
private const int CHUNKSIZE = 7056;
uint bytesread = 0;
var squares = new double[CHUNKSIZE / 4];
const double scale = 1.0d / 32768.0d;
do
{
result = sound.readData(data, CHUNKSIZE, ref read);
Marshal.Copy(data, buffer, 0, CHUNKSIZE);
//PCM samples are 16 bit little endian
Array.Reverse(buffer);
for (var i = 0; i < buffer.Length; i += 4)
{
var avg = scale * (Math.Abs((double)BitConverter.ToInt16(buffer, i)) + Math.Abs((double)BitConverter.ToInt16(buffer, i + 2))) / 2.0d;
squares[i >> 2] = avg * avg;
}
var rmsAmplitude = ((int)(Math.Floor(Math.Sqrt(squares.Average()) * 32768.0d))).ToString("X2");
fs.Write(buffer, 0, (int) read);
bytesread += read;
statusBar.Text = "writing " + bytesread + " bytes of " + length + " to output.raw";
} while (result == FMOD.RESULT.OK && read == CHUNKSIZE);
After loading mp3, seems my rmsAmplitude is in the range 3C00 to 4900. Have I done something wrong? I was expecting a wider spread.
Yes, a sample represents amplitude (at that point in time).
To get a spectrum, you typically convert it from the time domain to the frequency domain.
Last Q: Multiple approaches are used - You may want the RMS.
Generally, the x axis is the time value and y axis is the amplitude. To get the frequency, you need to take the Fourier transform of the data (most likely using the Fast Fourier Transform [fft] algorithm).
To use one of the simplest "sounds", let's assume you have a single frequency noise with frequency f. This is represented (in the amplitude/time domain) as y = sin(2 * pi * x / f).
If you convert that into the frequency domain, you just end up with Frequency = f.
Each sample represents the voltage of the analog signal at a given time.

Resources