pythonandroidaudiorecordchaquopybeeware

sample android phone mic using AudioRecord with Beeware


Beeware makes accessible the android.media classes MediaPlayer,Media.Recorder and AudioRecord from Python script and I already managed to play and record audio on galaxy23 with Beeware. However MediaRecorder does not provide PCM format output which is required for my application that is concerned with audio signal processing. AudioRecord is capable to sample the mic signal in PCM, however when I try to read the PCM data frames (according to AudioRecord docs https://developer.android.com/reference/android/media/AudioRecord) with read(byte[] ...) using a numpy array with dtype=np.int8 or dtype=np.byte or even trying to use read(float[] ...) with a numpy array with dtype=np.float32, I always get the same ambiguity error

android.media.AudioRecord.read is ambiguous for arguments (ndarray, int, int): options are int android.media.AudioRecord.read(byte[], int, int), int android.media.AudioRecord.read(short[], int, int)

It seems to me that AudioRecord cannot recognize my numpy array as byte[] format although np.int8 or np.byte are both signed byte as byte[] is in java, or even cannot recognize it as float[]format with np.float32. Can anybody help me find out what is wrong with what I do? any hint will be much appreciated

I would like to be able to correctly use AudioRecord as all third-party audio modules known to me are not accessible with Beeware even for converting (in-phone) MediaRecorder output file to PCM

UPDATE: Following the answer below by mhsmith I tried the suggestion and it WORKS GREAT!! many thanks! I include the relevant piece of code

def record_file(self,widget):
    #Create an AudioRecord object.
    self.source=MediaRecorder.AudioSource.MIC
    self.sampleRate=8000
    self.channel=AudioFormat.CHANNEL_IN_MONO
    self.encoding=AudioFormat.ENCODING_PCM_16BIT
    self.minBufferSize=AudioRecord.getMinBufferSize(self.sampleRate,self.channel,self.encoding)

    self.recorder=AudioRecord(self.source,self.sampleRate,self.channel,self.encoding,self.minBufferSize)
    self.recorder.startRecording()

    # Create a byte array to store the audio data.
    self.byteRate=2*self.sampleRate
    self.readTimePeriod=self.minBufferSize/self.byteRate
    self.readArray=np.zeros(self.minBufferSize,dtype=np.int8)
    self.audioData = jarray(jbyte)(self.readArray)

    while True:
    
        #Wait for the buffer to fill-in
        time.sleep(self.readTimePeriod)

        # Read audio data from the buffer.
        self.bytesRead = self.recorder.read(self.audioData,0,self.minBufferSize,0)
        
        # Get the audio data in numpy array from the byte array.
        for i in range(self.minBufferSize):            
             self.readArray[i]=self.audioData[i]

Solution

  • Chaquopy doesn't currently use the dtype of an ndarray when deciding which Java overload to use. This would be a useful feature, and I've created this issue to track it.

    Meanwhile, you can work around it by converting the ndarray to a Java array manually:

    from java import jarray, jbyte
    
    audio = np.array(..., dtype=np.int8)
    audio_record.read(jarray(jbyte)(audio), ...)