Advertisement
Kitomas

kpm_convert.py

Dec 15th, 2023
613
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.15 KB | None | 0 0
  1. #converts uncompressed pcm .wav files to mode 0 .kpm
  2. if __name__ != "__main__": exit(0) #lol
  3. from time import time
  4. from sys import argv
  5. from os import listdir, system as cmd
  6. from os.path import isfile, join
  7. import wave
  8.  
  9.  
  10.  
  11. #beeg line
  12. def getFilenames(fldr = "."): return [f for f in listdir(fldr) if isfile(join(fldr,f)) and f != argv[0].split("\\")[-1] and f.split(".")[-1] != "kpm"]
  13.  
  14. def getArgPath(indx):
  15.     try:
  16.         return argv[indx]
  17.     except IndexError:
  18.         return "." #current directory
  19.        
  20. def tryInt(string):
  21.     try:
  22.         return int(string)
  23.     except ValueError:
  24.         return None
  25.     except TypeError:
  26.         return None
  27.        
  28. def replaceExtension(filename,extension):
  29.     split = filename.split(".")[:-1]
  30.     if len(split) == 0: return filename + extension
  31.     else:               return (".").join(split) + extension
  32.  
  33.  
  34.  
  35. folderin  = getArgPath(1)
  36. folderout = getArgPath(2)
  37. filenames = None
  38. try:
  39.     filenames = getFilenames(folderin)
  40. except FileNotFoundError as err:
  41.     print(err)
  42.     exit(1)
  43.  
  44. if len(filenames) == 0:
  45.     print("folder \"{}\" is empty!".format(folderin))
  46.     cmd("pause")
  47.     exit(1)
  48.  
  49. which = None
  50. while which == None:
  51.     cmd("cls")
  52.  
  53.     print("input files in \"{}\":\n".format(folderin))
  54.  
  55.     for i in range(len(filenames)):
  56.         print("{:2}: \"{}\"".format(i,filenames[i]))
  57.  
  58.     result = input("\npick a .wav to convert (0 -> {}): ".format(len(filenames)-1))
  59.     which = tryInt(result)
  60.     if which == None: continue
  61.     if which<0 or which>=len(filenames): which = None
  62.  
  63.  
  64.  
  65. startTime = time()
  66.  
  67. #supported input SDL_AudioFormat types
  68. AUDIO_U8  = b'\x08\x00' #unsigned 8-bit samples
  69. AUDIO_S16 = b'\x10\x80' #signed 16-bit samples
  70. input_types = (None,AUDIO_U8,AUDIO_S16) #sorted by byte width
  71. input_types_str = (None,"AUDIO_U8","AUDIO_S16")
  72.  
  73. fileinPath = join(folderin,filenames[which])
  74. filein = None
  75. try:
  76.     filein = wave.open(fileinPath,"rb") #https://docs.python.org/3/library/wave.html
  77. except Exception as err:
  78.     print(err)
  79.     cmd("pause")
  80.     exit(1)
  81.    
  82. sampwidth   = filein.getsampwidth()
  83. nframes     = filein.getnframes()
  84. framerate   = filein.getframerate()
  85. nchannels   = filein.getnchannels()
  86. sample_data = filein.readframes(-1)
  87. filein.close()
  88.  
  89. if sampwidth < 1 or sampwidth > 2:
  90.     print("sample data is not of type AUDIO_U8 or AUDIO_S16!")
  91.     cmd("pause")
  92.     exit(1)
  93.  
  94.  
  95.  
  96. magic        = "kPCM" #4B
  97. format       = input_types[sampwidth] #2B
  98. headerSize   = 72 #2B
  99. dataSize     = len(sample_data) #8B
  100. loopStart    = 0 #8B
  101. loopEnd      = nframes #8B
  102. numSamples   = nframes #8B
  103. sampleRate   = framerate #4B
  104. bitRate      = framerate * sampwidth * nchannels * 8 #4B
  105. loopCount    = 0 #2B
  106. channels  = nchannels #2B
  107. bitRemainder = 0 #1B
  108. userflags    = 0 #1B
  109. mode         = 0 #2B
  110. userdata_a   = 0 #8B
  111. userdata_b   = 0 #8B
  112.  
  113. #iirc byte objects are immutable, but the header is only 72 bytes anyway
  114. le = "little" #[l]ittle [e]ndian (i wish python had macros)
  115. header_data  = bytes(magic,"ascii")        # 0x00: magic
  116. header_data += format                      # 0x04: format
  117. header_data += headerSize.to_bytes(  2,le) # 0x06: headerSize
  118. header_data += dataSize.to_bytes(    8,le) # 0x08: dataSize
  119. header_data += loopStart.to_bytes(   8,le) # 0x10: loopStart
  120. header_data += loopEnd.to_bytes(     8,le) # 0x18: loopEnd
  121. header_data += numSamples.to_bytes(  8,le) # 0x20: numSamples
  122. header_data += sampleRate.to_bytes(  4,le) # 0x28: sampleRate
  123. header_data += bitRate.to_bytes(     4,le) # 0x2C: bitRate
  124. header_data += loopCount.to_bytes(   2,le) # 0x30: loopCount
  125. header_data += channels.to_bytes(    2,le) # 0x32: channels
  126. header_data += bitRemainder.to_bytes(1,le) # 0x34: bitRemainder
  127. header_data += userflags.to_bytes(   1,le) # 0x35: userflags
  128. header_data += mode.to_bytes(        2,le) # 0x36: mode
  129. header_data += userdata_a.to_bytes(  8,le) # 0x38: userdata_a
  130. header_data += userdata_b.to_bytes(  8,le) # 0x40: userdata_b
  131.  
  132.  
  133.  
  134. fileoutPath = join(folderout,filenames[which])
  135. fileoutPath = replaceExtension(fileoutPath,".kpm")
  136.  
  137. fileout = open(fileoutPath,"wb")
  138.  
  139. fileout.write(header_data)
  140. fileout.write(sample_data)
  141.  
  142. fileout.close()
  143. timeTakenMS = (time()-startTime)*1000
  144.  
  145.  
  146. print("\noutput file info:")
  147. print(("  magic        = \"{}\"").format(magic))
  148. print(("  format       = {}").format(input_types_str[sampwidth]))
  149. print(("  headerSize   = {}").format(headerSize))
  150. print(("  dataSize     = {}").format(dataSize))
  151. print(("  loopStart    = {}").format(loopStart))
  152. print(("  loopEnd      = {}").format(loopEnd))
  153. print(("  numSamples   = {}").format(numSamples))
  154. print(("  sampleRate   = {}").format(sampleRate))
  155. print(("  bitRate      = {}").format(bitRate))
  156. print(("  loopCount    = {}").format(loopCount))
  157. print(("  channels     = {}").format(channels))
  158. print(("  bitRemainder = {}").format(bitRemainder))
  159. print(("  userflags    = {}").format(userflags))
  160. print(("  mode         = {}").format(mode))
  161. print(("  userdata_a   = {}").format(userdata_a))
  162. print(("  userdata_b   = {}").format(userdata_b))
  163.  
  164. print("\nsaved to: \"{}\"".format(fileoutPath))
  165. print("time taken: {:.4}ms".format(timeTakenMS))
  166. print("\npress any key to exit")
  167. cmd("pause >nul")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement