42

I have a .wav file several minutes long that I would like to split into different 10 second .wav files.

This is my python code so far:

import wave
import math

def main(filename, time):
    read = wave.open(filename, 'r')

#get sample rate
    frameRate = read.getframerate()

#get number of frames
    numFrames = read.getnframes()

#get duration
    duration = numFrames/frameRate

#get all frames as a string of bytes
    frames = read.readframes(numFrames)

#get 1 frame as a string of bytes
    oneFrame = read.readframes(1)

#framerate*time == numframesneeded
    numFramesNeeded=frameRate*time

#numFramesNeeded*oneFrame=numBytes
    numBytes = numFramesNeeded*oneFrame

#splice frames to get a list strings each representing a 'time' length
#wav file
    x=0
    wavList=[]
    while x+time<=duration:
        curFrame= frames[x:x+time]
        x=x+time
        wavList.append(curFrame)

Printing wavList yields:

['\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00']

I know that this is a list of frames. How do I make one wav file for each element in this list (the first .wav file would be '\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00'? Python's wave module is unclear about using frames to create .wav files.

EDIT: This is a duplicate question of How to splice an audio file (wav format) into 1 sec splices in python? However, if someone has an answer that does not require pydub I would very much like to see it.

martineau
  • 119,623
  • 25
  • 170
  • 301
jdsto
  • 455
  • 1
  • 4
  • 11
  • Possible duplicate of [How to splice an audio file (wav format) into 1 sec splices in python?](https://stackoverflow.com/questions/36799902/how-to-splice-an-audio-file-wav-format-into-1-sec-splices-in-python) – Nikana Reklawyks Sep 06 '18 at 20:58
  • `pydub` is obviously the straightforward way to do this task. It seems to me that what you're really asking for is code review. If you're asking about how to do the think at a lower level, why not just read the `pydub` code ? e.g. see [`get_sample_slice`](https://github.com/jiaaro/pydub/blob/master/pydub/audio_segment.py) and the manipulations of `._data` manipulations in general. – Nikana Reklawyks Sep 06 '18 at 21:03

3 Answers3

70

This is a python code snippet that I use for splitting files as per necessity.
I use the pydub library from https://github.com/jiaaro/pydub. You can modify the snippet to suit your requirement.

from pydub import AudioSegment
t1 = t1 * 1000 #Works in milliseconds
t2 = t2 * 1000
newAudio = AudioSegment.from_wav("oldSong.wav")
newAudio = newAudio[t1:t2]
newAudio.export('newSong.wav', format="wav") #Exports to a wav file in the current path.
siddhantsomani
  • 1,324
  • 13
  • 12
22

I've written a class to simplify the whole process. Although it's for wav files.

Here it is:

from pydub import AudioSegment
import math

class SplitWavAudioMubin():
    def __init__(self, folder, filename):
        self.folder = folder
        self.filename = filename
        self.filepath = folder + '\\' + filename
        
        self.audio = AudioSegment.from_wav(self.filepath)
    
    def get_duration(self):
        return self.audio.duration_seconds
    
    def single_split(self, from_min, to_min, split_filename):
        t1 = from_min * 60 * 1000
        t2 = to_min * 60 * 1000
        split_audio = self.audio[t1:t2]
        split_audio.export(self.folder + '\\' + split_filename, format="wav")
        
    def multiple_split(self, min_per_split):
        total_mins = math.ceil(self.get_duration() / 60)
        for i in range(0, total_mins, min_per_split):
            split_fn = str(i) + '_' + self.filename
            self.single_split(i, i+min_per_split, split_fn)
            print(str(i) + ' Done')
            if i == total_mins - min_per_split:
                print('All splited successfully')

Usage

folder = 'F:\\My Audios\\Khaled'
file = 'Khaled Speech.wav'
split_wav = SplitWavAudioMubin(folder, file)
split_wav.multiple_split(min_per_split=1)

That's it! It will split the single wav file into multiple wav files with 1 minute duration each. The last split audio may have less than 1-minute duration ;)

Note: If you're in Mac/Linux, then change \\ to /

Shariful Islam Mubin
  • 2,146
  • 14
  • 23
8

For those that come seeking an answer strictly for the wave module.

import wave

# times between which to extract the wave from
start = 5.2 # seconds
end = 78.3 # seconds

# file to extract the snippet from
with wave.open('my_in_file.wav', "rb") as infile:
    # get file data
    nchannels = infile.getnchannels()
    sampwidth = infile.getsampwidth()
    framerate = infile.getframerate()
    # set position in wave to start of segment
    infile.setpos(int(start * framerate))
    # extract data
    data = infile.readframes(int((end - start) * framerate))

# write the extracted data to a new file
with wave.open('my_out_file.wav', 'w') as outfile:
    outfile.setnchannels(nchannels)
    outfile.setsampwidth(sampwidth)
    outfile.setframerate(framerate)
    outfile.setnframes(int(len(data) / sampwidth))
    outfile.writeframes(data)
Lachlan
  • 360
  • 5
  • 14