In [3]:
import numpy as np
import librosa as lr
import librosa.display
In [4]:
# Read the audio file using librosa
y, sr = librosa.load('Ex3_sound1.wav')
In [5]:
# We need to convert from type float 32 to binary in order to extract the LSB.
# The following funciton do just that.
import struct
def binary(num):
    return ''.join('{:0>8b}'.format(c) for c in struct.pack('!f', num))

# Confirm the binary representation of the float is correct using the following online convertor
# https://www.h-schmidt.net/FloatConverter/IEEE754.html
for i in range(0,16):
    val = binary(y[i])
    print(val)

# Create empty list to save all the lsb values from every sample
lsbList = []

# Next we'll convert every sample in the audio file
for sample in y:
    binaryVal = binary(sample)
    lsbList.append(binaryVal[31])
    
print(lsbList[0:16])
10111011011001111000010001100010
10111011000110100101111111000011
10111011011011011110111001100000
10111011010100011010110111001100
10111011011010011100100011000011
10111011100010000000000011110001
10111011111001010111001101010110
10111100001100001111111001000111
10111011110100000010010110010100
10111100000011001101010010101101
10111011111111010001000101001000
10111100010001111100111010011100
10111011100110000000101001110111
10111011010010100011001010101110
10111011010001010101100001110000
00111011101011110110101010111100
['0', '1', '0', '0', '1', '1', '0', '1', '0', '1', '0', '0', '1', '0', '0', '0']
In [6]:
# Pair up the digits in pairs of 8 so that ASCI conversion to characters can be used
librosaString = "".join(chr(int("".join(map(str,lsbList[i:i+8])),2)) for i in range(0,len(lsbList),8))
print(librosaString[0:50])

# The text below does not make any sense. Try a different method.
MH—<ì+ð¢A³Dö‘éûnâa-ŽýZÐÚ& ŒìƯ~i³9Rí;èPM–R”­
In [7]:
# Open the audio file using wave
import wave
audio = wave.open("Ex3_sound1.wav", mode='rb')

# get the audio data
dataPoints = bytearray(list(audio.readframes(audio.getnframes())))

# Get the LSB of each byte using the bitwise method
lsbs = [dataPoints[i] & 1 for i in range(len(dataPoints))]

# add the lsbs together into pairs of 8 so that they can be converted into asci characters
asciChr = "".join(chr(int("".join(map(str,lsbs[i:i+8])),2)) for i in range(0,len(lsbs),8))

# We can already see the message here, but need to remove the # characters at the end of the string
print(asciChr[:50])

# split the text based on the # character and save the 1st section of the split
msg = asciChr.split("#")[0]

# Print the hidden message
print(msg)
audio.close()
Mom I will not be home for supper#################
Mom I will not be home for supper
In [8]:
# We can see wehere the error came in using librosa just by comparing the first 16 lsb bits
# Librosa loads audio samples as floats, so when converted to binary, the data differ from the wave method above.
print(lsbList[0:16]) # librosa library
print(lsbs[0:16]) # wave library
['0', '1', '0', '0', '1', '1', '0', '1', '0', '1', '0', '0', '1', '0', '0', '0']
[0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1]