From 4dc17d11ffdff1627e6fbfc10f3b5145836cda58 Mon Sep 17 00:00:00 2001 From: "Peder B. Sundt" Date: Tue, 27 Jan 2015 23:17:06 +0100 Subject: [PATCH] Added proper sound decoding --- PPM.py | 107 ++++++++++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/PPM.py b/PPM.py index c970dfa..3139605 100644 --- a/PPM.py +++ b/PPM.py @@ -6,11 +6,12 @@ # #Credits: # -# -Steven for most of the documentation on DSiBrew and his frame decoding example on his talkpage -# -Remark for help on the 8x8 tiling on the preview image. -# -Jsafive for supplying .tmb files +# - Steven for most of the documentation on DSiBrew and his frame decoding example on his talkpage +# - Remark for help on the 8x8 tiling on the preview image. +# - Jsafive for supplying .tmb files +# - Austin Burk, Midmad on hatena haiku and WDLmaster on hcs64.com for determining the sound codec # -import sys, wave#needs os and time aswell +import sys, wave, audioop#needs os and time aswell in CMD mode import numpy as np try: import Image @@ -241,7 +242,34 @@ class PPM: self.Thumbnail = out return self.Thumbnail - #sub functions: + def GetSound(self, index, outputpath=None):#index 0 is BGM. 1, 2 and 3 is SFX. if outputpath is None, the raw mono PCM @ 8kHz is returned instead + if self.Loaded[2]: + if self.SoundData[index]: + #reverse nibbles: + data = [] + for i in map(ord,self.SoundData[index]): + data.append(chr((i&0xF)<< 4 | (i>>4))) + data = "".join(data) + + #4bit ADPCM decode + decoded = audioop.adpcm2lin(data, 2, None)[0] + + #write to wav: + if outputpath: + f = wave.open(outputpath, "wb") + f.setnchannels(1) + f.setsampwidth(2) + f.setframerate(8000) + f.writeframes(decoded) + #f.writeframes("".join(out)) + f.close() + + return True + else: + return decoded + else: + return False + #sub functions: (private) def ExtractFrame(self, data, offset, PrevFrame=None): #defines line encoding storage: #Enc1 = [0 for i in range(192)] @@ -568,50 +596,12 @@ def WriteImage(image, outputPath): return True -#this is just for experimenting with sound decoding: -#not even remotely close to being finished -def DecodeSound(outputpath, data): - f = wave.open(outputpath, "wb") - f.setnchannels(1) - f.setsampwidth(2) - f.setframerate(32000) - for i in data: - i1 = ord(i)&0xF - i2 = (ord(i)>>4)&0xF - #Noise reduction: - #if i1&0x8: i1 = 0xF-(i1&0x7) - #if i2&0x8: i2 = 0xF-(i2&0x7) - i1 = i1&0x7 if i1&0x8 else 0xF-i1 - i2 = i2&0x7 if i2&0x8 else 0xF-i2 - f.writeframes(DecAsc(i1<<12, 2, True)*4) - f.writeframes(DecAsc(i2<<12, 2, True)*4) - f.close() -#testing: -# p = PPM() -# print "loading ppm..." -# p.ReadFile("PPMtests/test8.ppm", (1, 1, 1)) - -# print "Dumping Thumbnail..." -# WriteImage(p.Thumbnail, "thumbnail.png") - -# print "Dumping frames..." -# for i in xrange(p.FrameCount): - # WriteImage(p.GetFrame(i), "frames/frame %i.png" % i) - -# print "Dumping raw sounds..." -# for i, data in enumerate(p.SoundData): - # f = open("sound %i.bin" % i, "wb") - # f.write(data) - # f.close() - -# print "Extracting sounds...." -# for i, d in enumerate(p.SoundData): DecodeSound("out_%i.wav"%i, d) if __name__ == '__main__': print " == PPM.py ==" print " == by pbsds ==" - print " == v1.2 ==" + print " == v1.3 ==" print if len(sys.argv) < 3: @@ -621,9 +611,8 @@ if __name__ == '__main__': print " :" print " -t: Extracts the thumbnail to the file " print " -f: Extracts the frame(s) to " - print " -s: Dumps the raw sound data files to the folder " - print " -S: Same as mode 2, but will also dump the experimentally decoded" - print " sounds." + print " -s: Dumps the sound files to the folder " + print " -S: Same as mode -s, but will also dump the raw sound data files" print " -m: Prints out the metadata. Can also write it to which also" print " supports unicode charactes." print " Mode -t and -m supports TMB files aswell" @@ -709,22 +698,21 @@ if __name__ == '__main__': print "Done!" if not os.path.isdir(sys.argv[3]): - print "Error!\nThe specified directory doesn't exist!" + print "Error!\nThe specified output directory doesn't exist!" sys.exit() - print "Dumping the raw sound data...", + print "Converting the sound files...", for i, data in enumerate(flipnote.SoundData): - f = open(os.path.join(sys.argv[3], ("BGM.bin", "SFX1.bin", "SFX2.bin", "SFX3.bin")[i]), "wb") - f.write(data) - f.close() + if not data: continue + path = os.path.join(sys.argv[3], ("BGM.wav", "SFX1.wav", "SFX2.wav", "SFX3.wav")[i]) + flipnote.GetSound(i, path) + + if sys.argv[1] == "-S": + f = open(path[:-3]+"bin", "wb") + f.write(data) + f.close() print "Done!" - if sys.argv[1] == "-S": - print "Dumping the decoded sound data...", - for i, data in enumerate(flipnote.SoundData): - DecodeSound(os.path.join(sys.argv[3], ("BGM decoded.wav", "SFX1 decoded.wav", "SFX2 decoded.wav", "SFX3 decoded.wav")[i]), data) - print "Done!" - print "Dumping the sound effect usage...", f = open(os.path.join(sys.argv[3], "SFX usage.txt"), "w") for i, (s1, s2, s3) in enumerate(flipnote.SFXUsage): @@ -755,6 +743,7 @@ if __name__ == '__main__': meta.append(u"Locked: %s" % flipnote.Locked) if filetype == "ppm": meta.append(u"Frame speed: %s" % flipnote.Framespeed) + meta.append(u"Frame speed: %s" % flipnote.BGMFramespeed) meta.append(u"Looped: %s" % flipnote.Looped) meta.append(u"Thumbnail frame index: %i" % (flipnote.ThumbnailFrameIndex+1)) meta.append(u"Original author: %s" % flipnote.OriginalAuthorName) @@ -776,4 +765,4 @@ if __name__ == '__main__': f.write(newline.join(meta).encode("UTF-8")) f.close() else: - print "Error!\nThere's no such mode." \ No newline at end of file + print "Error!\nThere's no such mode."