bastibe / SoundCard

A Pure-Python Real-Time Audio Library
https://soundcard.readthedocs.io
BSD 3-Clause "New" or "Revised" License
680 stars 69 forks source link

Problem with the player #171

Open radio-satellites opened 1 year ago

radio-satellites commented 1 year ago

Hi!

Thank you so much for the great software! I'm trying to modulate AFSK via soundcard:

import sys, math
import soundcard as sc
import struct

class Modulator:

        #TODO: Bit-rate defined by periodsize...fix this by allowing bitrate to be an input
        def __init__(self, samplerate, periodsize, amplitude):
                self.samplerate = samplerate
                self.periodsize = periodsize
                self.amplitude = amplitude
                self.index = 0      #needed to keep phase continous
                self.speaker = sc.default_speaker()
                self.a = self.speaker.player(self.samplerate, channels=1, blocksize=self.periodsize)

    #Creates the signal in the form of signed, 16 bit samples which can be passed to the ALSA device
        def generate(self, freq):
                sine = [int((2**15-1)*self.amplitude*math.sin(2*math.pi*freq*x/self.samplerate)) \
                                for x in range(self.index, self.index + self.periodsize)]
                return sine

    #Takes a string and returns it as a string of raw little-endian binary (assuming ASCII input only)
        def string_to_bin(self, data):
                data = ''.join(['%x' % ord(n) for n in data])   #convert into a string of hex
                bin_string = '' 
                for n in data:
                        i = bin(int(n,16))[2:]          #convert each hex digit into binary
                        while len(i) < 4: i = '0' + i       #prepend binary with 0s as needed to make 4 bits long
                        bin_string += i             #add to string
                return bin_string

        def output(self, data):
                bin_string = self.string_to_bin(data)
                for n in bin_string:
                        if n == '1':
                                buff = self.generate(1200)
                        else:
                                buff = self.generate(2200)
                        self.a.play(buff)

However, I'm getting this error:

Traceback (most recent call last): File "D:/Documents/pyssdv/encode_packet.py", line 5, in <module> g.output("W2GMD>APRS:>Hello World!") File "D:\Documents/pyssdv\modulate_packet.py", line 46, in output self.a.play(buff) File "C:\Users\Sasha\AppData\Local\Programs\Python\Python311\Lib\site-packages\soundcard\mediafoundation.py", line 654, in play buffer = self._render_buffer(towrite) File "C:\Users\Sasha\AppData\Local\Programs\Python\Python311\Lib\site-packages\soundcard\mediafoundation.py", line 590, in _render_buffer hr = self._ppRenderClient[0][0].lpVtbl.GetBuffer(self._ppRenderClient[0], numframes, data) AttributeError: '_Player' object has no attribute '_ppRenderClient'. Did you mean: '_render_client'?

Could you please help? I'm not sure how to fix this.

Thank you so much!!

Sasha

bastibe commented 1 year ago

The player is a context manager that has to be used in a with, or with explicit __enter__ and __exit__ before you can play.