Consider this version of the sample generation function.
#Python pcm to wav generator#
The use of list comprehensions (and/or generator expressions) to build lists usually leads to more readable and faster code, at least when you're used to them. You might want to nest it in genFile or even merge it. Also, it doesn't make much sense to use on its own.
![python pcm to wav python pcm to wav](https://i.imgur.com/6BIBSJB.png)
GenHeader doesn't need to take the samples as a parameter since it depends only on the number of them. One way to help matters is to put the "input" parameter first and provide default values for (some of) the rest (e.g. Several functions take a lot of arguments which means they take more effort to use.
![python pcm to wav python pcm to wav](https://oscimg.oschina.net/oscnet/up-8cc5c0c2518d3e16d2b166b20097d9c0988.png)
![python pcm to wav python pcm to wav](https://www.codeproject.com/KB/audio-video/501521/mfresample.png)
(If you need multichannel at all otherwise this might be a good place to apply the YAGNI principle.) It would make more sense to me to handle any multichannel data as one list per channel, and let genFile be responsible for transforming it to the file format. Why this format? Probably because of how the Wav file is laid out on disk. Then we have genFile, which expects data in a list nested per-sample, and prepSamples is interlinked with this. It would be clearer to let genSamples return only samples and place the sweep generation in another function which uses it. The value c seems intimately connected to the frequency sweep functionality. GenSamples returns a tuple, which is rather unexpected at first.
#Python pcm to wav code#
Your functions are often interdependent in ways that make the code harder to grasp. We should strive for organizing code into independent, logical units (functions, classes. Prefer for sample in samples: over for i in range(len(samples)): Consider your API design IDEs or other tools may present them in various contexts. This means they can appear by typing help(function_name). """Generates samples for a given frequency, sample rate and durationĬ is the current amplitude of the wave between -1 and 1""" def genSamples(freq, sampleRate, duration, wave, c): They should be properly made as such, by putting them in triple quotes just after the function definitions. Your comments about each function are essentially docstrings. Until then I'd appreciate it if just the functionality of the code were to be critiqued.Īlso note that the current setup of the code takes some time to run and any performance gains that are possible would also be appreciated. I am aware of PEP8 and I am less interested in the styling of the code as this was just a quick write up to test what I'd been reading and to try out a couple of things, the code will be tidied when I more fully understand what I'm doing and how I want to continue.
#Python pcm to wav how to#
Any suggestions on how to improve the wave generation functionality would be greatly appreciated. # Use c to have waves of 1 frequency continue from where previousĬ, r = genSamples(i, 44100, 0.003003003003003, "sin", c)įrom this code review I'm most interested in comments w.r.t the genSamples function, the program as a whole seems to work well for frequencies between 20Hz and 18000Hz although there are some strange distortions after that as my sin wave becomes distorted (normally I wouldn't be able to hear 18kHz+ but as the the distortions are clearly audible). # This is just a temporary method until multiple channels is implemented # c is the current amplitude of the wave between -1 and 1ĭef genSamples(freq, sampleRate, duration, wave, c):Ĭ, samples = genSamples(freq,sampleRate,duration,'sin')
![python pcm to wav python pcm to wav](https://blog.kakaocdn.net/dn/307ka/btqDhva48oF/0Quk8NkmBpeWWnvYTS0we1/img.png)
# Generates samples for a given frequency, sample rate and duration # Samples are values between -1 and 1 then upscaled to the correct amplitude (-2**15 -> 2**15 roughly) for 16 bitĭef genFile(sampleRate, bitsPerSample, channels, samples):į.write(genHeader(sampleRate, bitsPerSample, channels, samples))į.write(int(samples * m).to_bytes(bitsPerSample//8,'little',signed=True)) O += (datasize).to_bytes(4,'little') # (4byte) Data size in bytes O += bytes("data",'ascii') # (4byte) Data Chunk Marker O += (bitsPerSample).to_bytes(2,'little') # (2byte) O += (channels * bitsPerSample // 8).to_bytes(2,'little') # (2byte) O += (sampleRate * channels * bitsPerSample // 8).to_bytes(4,'little') # (4byte) O += (16).to_bytes(4,'little') # (4byte) Length of above format data O += bytes("fmt ",'ascii') # (4byte) Format Chunk Marker O += bytes("WAVE",'ascii') # (4byte) File type O += (datasize + 36).to_bytes(4,'little') # (4byte) File size in bytes excluding this and RIFF marker O = bytes("RIFF",'ascii') # (4byte) Marks file as RIFF wav file header for a given set of samples and specsĭef genHeader(sampleRate, bitsPerSample, channels, samples):ĭatasize = len(samples) * channels * bitsPerSample // 8 wav file generator that I wrote briefly while (re)learning about audio sampling: import math