Okay, here's what I am up to now. I am trying to figure out how to write sin waves to a .wav file, for playback. Here's the issue: I have no idea what I'm doing. I looked up the documentation for the wave module, and have been able to open a wav file and write to it. It'll save a .wav file for a number of seconds, playing a frequency. Here's the code for that:

import numpy as N
import wave

# Here, create all files to playback
class SoundFile:

    def __init__(self, duration=5, frequency=400, samplerate=44100):
        sr = samplerate
        samples = duration*samplerate
        period = samplerate / float(frequency)
        omega = N.pi * 2 / period
        xaxis = N.arange(int(period),dtype = N.float) * omega
        ydata = 16384 * N.sin(xaxis)
        signal = N.resize(ydata, (samples,))
        ssignal = ''
        for i in range(len(signal)):
           ssignal += wave.struct.pack('h',signal[i])
        filewriteto = frequency
        self.file = wave.open(str(filewriteto)+'.wav', 'wb')
        self.file.setparams((1, 2, sr, 44100*4, 'NONE', 'noncompressed'))
        self.file.writeframes(ssignal)
        self.file.close()

# Test that the soundfile class works
S = SoundFile(5, 220)

I have a small gist of what's going on here. Now, I know how sine wavs work, and can add/subtract them. The only issue I have is writing them. No, I don't want a premade module for it. I don't even know if there's anything that exists for it. I've googled multiple times for information, but none have been found by me.
So, I guess what I need help with is just writing sine waves to a .wav file.
Any help would be much appreciated :D

Dani AI

Generated

The thread shows the right idea: generate samples, pack them, and write a RIFF/WAVE file. The main practical improvements are performance, correctness (sample format and header fields), and safety: avoid per-sample string concatenation and using eval() to build waveforms. supplied a working example and posted a chord-writer; both demonstrate the basic flow but can be made simpler and much faster by vectorizing sample generation and writing the whole buffer at once.

A compact, robust pattern is:

  • build a time vector and sum sinusoids with NumPy,
  • normalize to avoid clipping and map floats into 16-bit signed PCM,
  • open the file in binary write mode, set channels/sampwidth/framerate, then write the bytes buffer in one call.

Example (Python 3 + NumPy):

import numpy as np
import wave

def write_sine_wav(path, freqs, duration, sr=44100, amplitude=0.9):
    t = np.linspace(0, duration, int(sr*duration), endpoint=False)
    sig = np.sum([np.sin(2*np.pi*f*t) for f in freqs], axis=0)
    sig /= np.max(np.abs(sig))  # normalize
    sig *= amplitude
    samples = (sig * 32767).astype(np.int16)
    with wave.open(path, 'wb') as wf:
        wf.setnchannels(1)
        wf.setsampwidth(2)
        wf.setframerate(sr)
        wf.writeframes(samples.tobytes())

Notes and quick troubleshooting

  • Use 16-bit signed (int16) for common PCM; scaling factor is 32767. For 8-bit PCM the data is unsigned and needs an offset of 128.
  • WAV is little-endian PCM; using astype('<i2') forces little-endian if needed.
  • In Python 3, writeframes() expects bytes; avoid building a large Python string in a loop (slow and memory-inefficient). tobytes() or bytearray is the right approach.
  • Avoid eval() to construct waveforms — accept a callable or build expressions with NumPy for safety and speed.
  • For stereo, interleave channels (e.g., np.column_stack((L,R)).ravel()), then cast and write.

References: Python wave module (docs), NumPy ndarray.tobytes() (docs), WAV format overview (WAV).

Recommended Answers

All 2 Replies

Thank you very much vegaseat. You have helped me greatly. I am going to be making a module for music, with a scale, interval, and chord finder, along with the ability to write what you type in. I am hoping to make it into a nice synthesizer on the computer. I'm not sure though. Anyways, without further ado, here is the semi-finished code for writing a chord to a .wav file:

# .wav file chord writer
# ~ Hondros
# Much thanks to vegaseat
try:
    from numpy import *
except:
    try:
        from math import *
    except:
        print("No module numpy or math found;\nThese are vital for the performance of this program")
import struct
import wave

class SoundFile():

    def __init__(self,
                 freq=[440],
                 data_size=10000,
                 fname="test.wav",
                 frate=11025.0,
                 amp=8000.0,
                 functions = None):
        """Create a synthetic wave file,
           with combined frequencies freq,
           file fname has a length of about data_size*2
           Note if you want a certain wav other than sin,
           type function as a string, replacing frequenice as: 'freq'"""

        if functions == None:
            def func(number, x, frate, function):
                function = ''
                for frequencie in number:
                    a = 'sin(2*pi*'+str(frequencie)+'*(x/frate))+'
                    function += a
                function = function[:-1]
                return eval(function)

        if type(functions) == type(""):
            def func(number, x, frate, function):
                numfunction = ''
                for frequencie in number:
                    for splits in function.split('freq'):
                        numfunction += splits +\
                                       str(frequencie)
                        numfunction = numfunction[:-len(str(frequencie))]
                    numfunction += 'x'
                numfunction = numfunction[:-1]
                return eval(numfunction)

        sine_list = []
        for x in range(data_size):
            sine_list.append(func(freq, x, frate, functions))
        wavfile = wave.open(fname, "w")
        nchannels = 1
        sampwidth = 2
        framerate = int(frate)
        nframes = data_size
        comptype = "NONE"
        compname = "not compressed"
        wavfile.setparams((nchannels,
                            sampwidth,
                            framerate,
                            nframes,
                            comptype,
                            compname))
        print("Please be patient whilst the file is written")
        for s in sine_list:
            wavfile.writeframes(struct.pack('h', int(s*amp/2)))
        wavfile.close()
        print("%s written" %(fname))
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.