|
|
|
10-23-2020, 09:45 PM
|
#1
|
Human being with feelings
Join Date: Sep 2014
Posts: 2,643
|
Read ACID Info from source WAV [SOLVED]
I need to read the source wav file, Reaper will read the bpm but I need to read the other info like root note.
Here's Acidizer.zip if you are using Win 10 run it in Vista compatibility mode.
Code:
** The acid chunk goes a little something like this:
**
** 4 bytes 'acid'
** 4 bytes (int) length of chunk starting at next byte
**
** 4 bytes (int) type of file:
** this appears to be a bit mask,however some combinations
** are probably impossible and/or qualified as "errors"
**
** 0x01 On: One Shot Off: Loop
** 0x02 On: Root note is Set Off: No root
** 0x04 On: Stretch is On, Off: Strech is OFF
** 0x08 On: Disk Based Off: Ram based
** 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON)
**
** 2 bytes (short) root note
** if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B]
** if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47]
** (both types fit on same MIDI pitch albeit different octaves, so who cares)
**
** 2 bytes (short) ??? always set to 0x8000
** 4 bytes (float) ??? seems to be always 0
** 4 bytes (int) number of beats
** 2 bytes (short) meter denominator //always 4 in SF/ACID
** 2 bytes (short) meter numerator //always 4 in SF/ACID
** //are we sure about the order?? usually its num/denom
** 4 bytes (float) tempo
Last edited by MusoBob; 11-29-2020 at 06:21 PM.
|
|
|
11-26-2020, 06:50 PM
|
#2
|
Human being with feelings
Join Date: Sep 2014
Posts: 2,643
|
I wrote one for you here MusoBob.
So now you can make a script to fit bass loops to the chord track.
EDIT: It to read the selected item source.
Code:
--------------------------------------------------------------------------
-- script to extract information placed by ACID in a wav file --
--------------------------------------------------------------------------
--Information structure
-----------------------
-- 4 bytes 'acid' the signature of the start of the information block
-- 4 bytes (int) length of chunk starting at next byte
--
-- 4 bytes (int) type of file:
-- this appears to be a bit mask,however some combinations
-- are probably impossible and/or qualified as "errors"
--
-- 0x01 On: One Shot Off: Loop
-- 0x02 On: Root note is Set Off: No root
-- 0x04 On: Stretch is On, Off: Strech is OFF
-- 0x08 On: Disk Based Off: Ram based
-- 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON)
--
-- 2 bytes (short) root note
-- if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B]
-- if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47]
-- (both types fit on same MIDI pitch albeit different octaves, so who cares)
--
-- 2 bytes (short) ??? always set to 0x8000
-- 4 bytes (float) ??? seems to be always 0
-- 4 bytes (int) number of beats
-- 2 bytes (short) meter denominator //always 4 in SF/ACID
-- 2 bytes (short) meter numerator //always 4 in SF/ACID
-- //are we sure about the order?? usually its num/denom
-- 4 bytes (float) tempo
--
function print(value)
reaper.ShowConsoleMsg(tostring(value) .. "\n")
end
function round(val, decimal)
local exp = decimal and 10^decimal or 1
return math.ceil(val * exp - 0.5) / exp
end
-- convert hex to floating point routine
----------------------------------------
tab={["0"]="0000",["1"]="0001",["2"]="0010",["3"]="0011",
["4"]="0100",["5"]="0101",["6"]="0110",["7"]="0111",
["8"]="1000",["9"]="1001",["a"]="1010",["b"]="1011",
["c"]="1100",["d"]="1101",["e"]="1110",["f"]="1111",
["A"]="1010",["B"]="1011",["C"]="1100",["D"]="1101",["E"]="1110",["F"]="1111"}
function hexToFloat(str)
local str1=""
local a,z
for z=1,string.len(str) do
a=string.sub(str,z,z)
str1=str1..tab[a]
end
local pm=string.sub(str1,1,1)
local exp=string.sub(str1,2,9)
local c=tonumber(exp,2)-127
local p=2^c
local man="1"..string.sub(str1,10,32)
local x=0
for z=1,string.len(man) do
if string.sub(man,z,z)=="1" then
x=x+p
end
p=p/2
end
if pm=="1" then
x= -x
end
return(x)
end
--main routine
---------------------------------------------------------------------------------------------
sel_item = reaper.GetSelectedMediaItem( 0, 0 )
if not sel_item then goto finish end
item_take = reaper.GetMediaItemTake( sel_item, 0 )
source = reaper.GetMediaItemTake_Source( item_take )
filename = reaper.GetMediaSourceFileName(source, "")
local f = assert(io.open(filename, "rb"))
local byte_count = f:seek("end")
print("file has ", byte_count, " bytes")
i = 1
while true do
f:seek("set", byte_count - i)
read_byte4 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte4))
--print(current_byte)
if current_byte == "64" then --get next byte
f:seek("set", byte_count - i -1)
read_byte3 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte3))
if current_byte == "69" then --get next byte
f:seek("set", byte_count - i - 2)
read_byte2 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte2))
if current_byte == "63" then --get next byte
f:seek("set", byte_count - i - 3)
read_byte1 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte1))
if current_byte == "61" then break
end
end
end
end
i = i +1
--if i >= byte_count - 5 then print("File has not been ACIDized, no 'acid' signature found") fail = true break end
if i > 1000 then
print("File has not been ACIDized, no 'acid' signature found")
fail = true
break goto finish end
end
if not fail then
data_start = byte_count - i + 1
print("data starts at byte ", data_start)
--read data bytes
-------------------------
f:seek("set", data_start)
chunk_length4 = f:read(1)
chunk_length3 = f:read(1)
chunk_length2 = f:read(1)
chunk_length1 = f:read(1)
current_data = string.format("%02X",string.byte(chunk_length1))..string.format("%02X",string.byte(chunk_length2))..string.format("%02X",string.byte(chunk_length3))..string.format("%02X",string.byte(chunk_length4))
print("ACID info chunk length (4 Bytes)= ".. current_data)
print("ACID info chunk length (decimal)= ".. tonumber(current_data, 16))
-----------------------------------
file_type4 = string.byte(f:read(1))
file_type3 = string.byte(f:read(1))
file_type2 = string.byte(f:read(1))
file_type1 = string.byte(f:read(1))
current_data = string.format("%02X", file_type1)..string.format("%02X", file_type2)..string.format("%02X", file_type3)..string.format("%02X", file_type4)
print("file type (4 Bytes)= ", current_data)
if (string.byte(file_type4) & 0x01)~= 0 then print("\t\t\tOne shot") else print("\t\t\tLoop") end
if (string.byte(file_type4) & 0x02)~= 0 then print("\t\t\tRoot note is set") else print("\t\t\tNo root note") end
if (string.byte(file_type4) & 0x04)~= 0 then print("\t\t\tStretch is on") else print("\t\t\tStretch is off") end
if (string.byte(file_type4) & 0x08)~= 0 then print("\t\t\tDisk based") else print("\t\t\tRAM based") end
if (string.byte(file_type4) & 0x10)~= 0 then print("\t\t\tbit 4 set") else print("\t\t\tbit 4 off") end
if (string.byte(file_type4) & 0x20)~= 0 then print("\t\t\tbit 5 set") else print("\t\t\tbit 5 off") end
if (string.byte(file_type4) & 0x40)~= 0 then print("\t\t\tbit 6 set") else print("\t\t\tbit 6 off") end
if (string.byte(file_type4) & 0x80)~= 0 then print("\t\t\tbit 7 set") else print("\t\t\tbit 7 off") end
----------------------
root_note2 = f:read(1)
root_note1 = f:read(1)
current_data = string.format("%02X",string.byte(root_note1))..string.format("%02X",string.byte(root_note2))
print("root note (2 Bytes)= ".. current_data)
notes = {
"C#-1","D-1","D#-1","E-1","F-1","F#-1","G-1","G#-1","A-1","A#-1","B-1",
"C0","C#0","D0","D#0","E0","F0","F#0","G0","G#0","A0","A#0","B0",
"C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1","A1","A#1","B1",
"C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2",
"C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3",
"C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4",
"C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5","A5","A#5","B5",
"C6","C#6","D6","D#6","E6","F6","F#6","G6","G#6","A6","A#6","B6",
"C7","C#7","D7","D#7","E7","F7","F#7","G7","G#7","A7","A#7","B7",
"C8","C#8","D8","D#8","E8","F8","F#8","G8","G#8","A8","A#8","B8",
"C9","C#9","D9","D#9","E9","F9","F#9","G9","G#9","A9","A#9","B9",
"C10","C#10","D10","D#10","E10","F10","F#10","G10","G#10","A10","A#10","B10"}
print("Root note is:\t\t".. notes[tonumber(current_data, 16)])
-------------------------
always_8000_2 = f:read(1)
always_8000_1 = f:read(1)
current_data = string.format("%02X",string.byte(always_8000_1))..string.format("%02X",string.byte(always_8000_2))
print("always 8000 (2 Bytes)= ".. current_data)
----------------------
always_0_4 = f:read(1)
always_0_3 = f:read(1)
always_0_2 = f:read(1)
always_0_1 = f:read(1)
current_data = string.format("%02X",string.byte(always_0_1))..string.format("%02X",string.byte(always_0_2))..string.format("%02X",string.byte(always_0_3))..string.format("%02X",string.byte(always_0_4))
print("always 00000000 (4 Bytes)= ".. current_data)
----------------------
num_beats4 = f:read(1)
num_beats3 = f:read(1)
num_beats2 = f:read(1)
num_beats1 = f:read(1)
current_data = string.format("%02X",string.byte(num_beats1))..string.format("%02X",string.byte(num_beats2))..string.format("%02X",string.byte(num_beats3))..string.format("%02X",string.byte(num_beats4))
print("number of beats (4 Bytes)= ".. current_data)
----------------------
meter_den2 = f:read(1)
meter_den1 = f:read(1)
current_data = string.format("%02X",string.byte(meter_den1))..string.format("%02X",string.byte(meter_den2))
print("meter_denominator = (2 Bytes)".. current_data)
----------------------
meter_num2 = f:read(1)
meter_num1 = f:read(1)
current_data = string.format("%02X",string.byte(meter_num1))..string.format("%02X",string.byte(meter_num2))
print("meter_numerator = (2 Bytes)".. current_data)
---------------------
--unknown = f:read(2)
--current_data = string.format("%04X",string.byte(unknown))
--print("unknown = ", current_data)
------------------
tempo4 = f:read(1)
tempo3 = f:read(1)
tempo2 = f:read(1)
tempo1 = f:read(1)
current_data = string.format("%02X",string.byte(tempo1))..string.format("%02X",string.byte(tempo2))..string.format("%02X",string.byte(tempo3))..string.format("%02X",string.byte(tempo4))
print("tempo (4 Bytes)= ".. current_data)
print("tempo decimal = ".. hexToFloat(current_data))
end
assert(f:close())
::finish::
Last edited by MusoBob; 11-30-2020 at 11:43 PM.
|
|
|
11-30-2020, 10:51 PM
|
#3
|
Human being with feelings
Join Date: Sep 2014
Posts: 2,643
|
This one should work better:
Code:
--------------------------------------------------------------------------
-- script to extract information placed by ACID in a wav file --
--------------------------------------------------------------------------
--Information structure
-----------------------
-- 4 bytes 'acid' the signature of the start of the information block
-- 4 bytes (int) length of chunk starting at next byte
--
-- 4 bytes (int) type of file:
-- this appears to be a bit mask,however some combinations
-- are probably impossible and/or qualified as "errors"
--
-- 0x01 On: One Shot Off: Loop
-- 0x02 On: Root note is Set Off: No root
-- 0x04 On: Stretch is On, Off: Strech is OFF
-- 0x08 On: Disk Based Off: Ram based
-- 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON)
--
-- 2 bytes (short) root note
-- if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B]
-- if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47]
-- (both types fit on same MIDI pitch albeit different octaves, so who cares)
--
-- 2 bytes (short) ??? always set to 0x8000
-- 4 bytes (float) ??? seems to be always 0
-- 4 bytes (int) number of beats
-- 2 bytes (short) meter denominator //always 4 in SF/ACID
-- 2 bytes (short) meter numerator //always 4 in SF/ACID
-- //are we sure about the order?? usually its num/denom
-- 4 bytes (float) tempo
--
function print(value)
reaper.ShowConsoleMsg(tostring(value) .. "\n")
end
function round(val, decimal)
local exp = decimal and 10^decimal or 1
return math.ceil(val * exp - 0.5) / exp
end
-- convert hex to floating point routine
----------------------------------------
tab={["0"]="0000",["1"]="0001",["2"]="0010",["3"]="0011",
["4"]="0100",["5"]="0101",["6"]="0110",["7"]="0111",
["8"]="1000",["9"]="1001",["a"]="1010",["b"]="1011",
["c"]="1100",["d"]="1101",["e"]="1110",["f"]="1111",
["A"]="1010",["B"]="1011",["C"]="1100",["D"]="1101",["E"]="1110",["F"]="1111"}
function hexToFloat(str)
local str1=""
local a,z
for z=1,string.len(str) do
a=string.sub(str,z,z)
str1=str1..tab[a]
end
local pm=string.sub(str1,1,1)
local exp=string.sub(str1,2,9)
local c=tonumber(exp,2)-127
local p=2^c
local man="1"..string.sub(str1,10,32)
local x=0
for z=1,string.len(man) do
if string.sub(man,z,z)=="1" then
x=x+p
end
p=p/2
end
if pm=="1" then
x= -x
end
return(x)
end
--main routine
---------------------------------------------------------------------------------------------
sel_item = reaper.GetSelectedMediaItem( 0, 0 )
if not sel_item then goto finish end
item_take = reaper.GetMediaItemTake( sel_item, 0 )
source = reaper.GetMediaItemTake_Source( item_take )
filename = reaper.GetMediaSourceFileName(source, "")
local f = assert(io.open(filename, "rb"))
local byte_count = f:seek("end")
print("file has ", byte_count, " bytes")
i = 1
while true do
f:seek("set", byte_count - i)
read_byte4 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte4))
--print(current_byte)
if current_byte == "64" then --get next byte
f:seek("set", byte_count - i -1)
read_byte3 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte3))
if current_byte == "69" then --get next byte
f:seek("set", byte_count - i - 2)
read_byte2 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte2))
if current_byte == "63" then --get next byte
f:seek("set", byte_count - i - 3)
read_byte1 = f:read(1)
current_byte = string.format("%02X",string.byte(read_byte1))
if current_byte == "61" then break
end
end
end
end
i = i +1
--if i >= byte_count - 5 then print("File has not been ACIDized, no 'acid' signature found") fail = true break end
if i > 1000 then
print("File has not been ACIDized, no 'acid' signature found")
fail = true
break goto finish end
end
if not fail then
data_start = byte_count - i + 1
print("data starts at byte ", data_start)
--read data bytes
-------------------------
f:seek("set", data_start)
chunk_length4 = f:read(1)
chunk_length3 = f:read(1)
chunk_length2 = f:read(1)
chunk_length1 = f:read(1)
current_data = string.format("%02X",string.byte(chunk_length1))..string.format("%02X",string.byte(chunk_length2))..string.format("%02X",string.byte(chunk_length3))..string.format("%02X",string.byte(chunk_length4))
print("ACID info chunk length (4 Bytes)= ".. current_data)
print("ACID info chunk length (decimal)= ".. tonumber(current_data, 16))
-----------------------------------
file_type4 = string.byte(f:read(1))
file_type3 = string.byte(f:read(1))
file_type2 = string.byte(f:read(1))
file_type1 = string.byte(f:read(1))
current_data = string.format("%02X", file_type1)..string.format("%02X", file_type2)..string.format("%02X", file_type3)..string.format("%02X", file_type4)
print("file type (4 Bytes)= ", current_data)
if (string.byte(file_type4) & 0x01)~= 0 then print("\t\t\tOne shot") else print("\t\t\tLoop") end
if (string.byte(file_type4) & 0x02)~= 0 then print("\t\t\tRoot note is set") else print("\t\t\tNo root note") end
if (string.byte(file_type4) & 0x04)~= 0 then print("\t\t\tStretch is on") else print("\t\t\tStretch is off") end
if (string.byte(file_type4) & 0x08)~= 0 then print("\t\t\tDisk based") else print("\t\t\tRAM based") end
if (string.byte(file_type4) & 0x10)~= 0 then print("\t\t\tbit 4 set") else print("\t\t\tbit 4 off") end
if (string.byte(file_type4) & 0x20)~= 0 then print("\t\t\tbit 5 set") else print("\t\t\tbit 5 off") end
if (string.byte(file_type4) & 0x40)~= 0 then print("\t\t\tbit 6 set") else print("\t\t\tbit 6 off") end
if (string.byte(file_type4) & 0x80)~= 0 then print("\t\t\tbit 7 set") else print("\t\t\tbit 7 off") end
----------------------
root_note2 = f:read(1)
root_note1 = f:read(1)
current_data = string.format("%02X",string.byte(root_note1))..string.format("%02X",string.byte(root_note2))
print("root note (2 Bytes)= ".. current_data)
notes = {
"C#-1","D-1","D#-1","E-1","F-1","F#-1","G-1","G#-1","A-1","A#-1","B-1",
"C0","C#0","D0","D#0","E0","F0","F#0","G0","G#0","A0","A#0","B0",
"C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1","A1","A#1","B1",
"C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2",
"C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3",
"C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4",
"C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5","A5","A#5","B5",
"C6","C#6","D6","D#6","E6","F6","F#6","G6","G#6","A6","A#6","B6",
"C7","C#7","D7","D#7","E7","F7","F#7","G7","G#7","A7","A#7","B7",
"C8","C#8","D8","D#8","E8","F8","F#8","G8","G#8","A8","A#8","B8",
"C9","C#9","D9","D#9","E9","F9","F#9","G9","G#9","A9","A#9","B9",
"C10","C#10","D10","D#10","E10","F10","F#10","G10","G#10","A10","A#10","B10"}
print("Root note is:\t\t".. notes[tonumber(current_data, 16)])
-------------------------
always_8000_2 = f:read(1)
always_8000_1 = f:read(1)
current_data = string.format("%02X",string.byte(always_8000_1))..string.format("%02X",string.byte(always_8000_2))
print("always 8000 (2 Bytes)= ".. current_data)
----------------------
always_0_4 = f:read(1)
always_0_3 = f:read(1)
always_0_2 = f:read(1)
always_0_1 = f:read(1)
current_data = string.format("%02X",string.byte(always_0_1))..string.format("%02X",string.byte(always_0_2))..string.format("%02X",string.byte(always_0_3))..string.format("%02X",string.byte(always_0_4))
print("always 00000000 (4 Bytes)= ".. current_data)
----------------------
num_beats4 = f:read(1)
num_beats3 = f:read(1)
num_beats2 = f:read(1)
num_beats1 = f:read(1)
current_data = string.format("%02X",string.byte(num_beats1))..string.format("%02X",string.byte(num_beats2))..string.format("%02X",string.byte(num_beats3))..string.format("%02X",string.byte(num_beats4))
print("number of beats (4 Bytes)= ".. current_data)
----------------------
meter_den2 = f:read(1)
meter_den1 = f:read(1)
current_data = string.format("%02X",string.byte(meter_den1))..string.format("%02X",string.byte(meter_den2))
print("meter_denominator = (2 Bytes)".. current_data)
----------------------
meter_num2 = f:read(1)
meter_num1 = f:read(1)
current_data = string.format("%02X",string.byte(meter_num1))..string.format("%02X",string.byte(meter_num2))
print("meter_numerator = (2 Bytes)".. current_data)
---------------------
--unknown = f:read(2)
--current_data = string.format("%04X",string.byte(unknown))
--print("unknown = ", current_data)
------------------
tempo4 = f:read(1)
tempo3 = f:read(1)
tempo2 = f:read(1)
tempo1 = f:read(1)
current_data = string.format("%02X",string.byte(tempo1))..string.format("%02X",string.byte(tempo2))..string.format("%02X",string.byte(tempo3))..string.format("%02X",string.byte(tempo4))
print("tempo (4 Bytes)= ".. current_data)
print("tempo decimal = ".. hexToFloat(current_data))
end
assert(f:close())
::finish::
Last edited by MusoBob; 11-30-2020 at 11:43 PM.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 12:58 AM.
|