Giter Club home page Giter Club logo

Comments (5)

miketeachman avatar miketeachman commented on June 14, 2024

I assume you would like to mix together the samples from the audio wav files and play using one speaker.

Here is some pseudo-code showing one possible approach, for mixing together audio samples from two wave files:

construct I2S object with sample rate, bit size, etc
define a bytearray buffer 1, 2000 bytes in length
define a bytearray buffer 2, 2000 bytes in length
define a bytearray buffer 3, 2000 bytes in length
open wav file 1
open wav file 2

loop:
  read audio samples from wav file 1 into buffer 1
  read audio samples from wav file 2 into buffer 2
  add the samples from buffers 1 and 2, store results in buffer 3
  write samples from buffer 3 to I2S object using the I2S.write() method

notes:

I hope this will help you to get started !

from micropython-i2s-examples.

limchr avatar limchr commented on June 14, 2024

Exactly this was also my question! But first things first: Thanks for your efforts. Especially the nice examples section is really helpful to get started.

In terms of the mixing of samples I have an additional demand, and I thought about solutions for solving this. I am going to program a sampler for a modular synthesizer, that have 8 triggers (either CV or push buttons) and than plays up to 8 wavs through 1 output via a i2s amplifier (98357A).

However, the problem is, that wavs can be played at any time. So e.g. the first wav is triggered, then after 500ms the second is triggered and so on and so on. Having a potential unlimited overlap of sample but a 'play buffer' of a limited size.

So my thoughts would be, add the samples dynamically into the play buffer at certain positions (when a trigger occurs) and if at the end of the buffer, doing a modulo operation for continuing at the start again (like a ring buffer).

Do you think, this would be the easiest method for doing this? This would also limit the volume of the samples, preventing a possible overflow (say for playing up to 3 samples simultaneously the max volume of all samples have to be 1/3 of max bitrate).

I also saw on other i2s implementations that they support the playback of multiple buffers. Is this part of the i2s protocol and thus could be implemented here too, or is this also coded on top?

Thanks again and I would appreciate any answer or suggestion

from micropython-i2s-examples.

limchr avatar limchr commented on June 14, 2024

I've came to a solution and it's working really good so far. Here it is:

@micropython.viper
def set_buffer(buf:ptr8, start_i:int, end_i:int, value:int):
	for i in range(start_i,end_i):
		buf[i] = value

@micropython.viper
def add_to_buffer(buf1:ptr8, buf2:ptr8, s_i1:int, s_i2:int, l:int):
	for i in range(l):
		buf1[s_i1+i] += buf2[s_i2+i]


# loop through ring buffer and mix together simultaneously playing wav files in play buffer
try:
	while True:
		utils.set_buffer(pbmv,0,pbl,0)
		for i,p in enumerate(trigger.is_playing):
			if p:
				add_l = min(pbl, len(wavs[i].data)-trigger.play_i[i])
				if add_l > 0:
					utils.add_to_buffer(pbmv,wavs[i].data,0,trigger.play_i[i],add_l)
					trigger.play_i[i] += add_l
				else:
					trigger.is_playing[i] = False
					trigger.play_i[i] = 0
		_ = audio_out.write(pbmv)
except (KeyboardInterrupt, Exception) as e:
	print("caught exception {} {}".format(type(e).__name__, e))

The triggers that are triggering samples to be played are set by timer interrupts checking for push button presses or control voltages. The buffer functions I have adapted from the forum thread you posted.

However, it is really strange but if I don't play a sample for like 2,3 seconds and after this time a sample is triggered, I hear a loud noise (like a cracking sound) at the beginning of the sample. All follow up samples don't have this noise, only if I wait longer than a few seconds, this noise appears. Could the reason be the i2s implementation? I checked my hardware setup, and I could not find any issues.

from micropython-i2s-examples.

miketeachman avatar miketeachman commented on June 14, 2024

Thank you for sharing your implementation! For the noise problem, I don't have an obvious solution, but I wonder if there is something inside the ESP32 I2S implementation that causes this? I submitted a PR in late 2021, trying to fix a noise problem when underflow happens, but it appears that there is still a problem with the ESP32 I2S implementation. A user reported this:
micropython/micropython@0be3b91#r61208899

As a workaround, is it possible to continually write a buffer of zero-value samples when no sample clips need to be played?

from micropython-i2s-examples.

limchr avatar limchr commented on June 14, 2024

Thanks, the noise issue seemed to be a hardware issue which is solved now. Also I am already writing 0's if no sample is in the queue.

It is working nicely now. However, I still have one hack in it: the add_to_buffer function doesn't care for overflows. Right now I solve it by decreasing the volume of samples, which is not optimal.

Since I'm adding 16bit signed integers within two buffers, I think I had to implement it manually. I thought of, adding the low significant byte, check for an overflow, if so add 1 to the higher byte, check for an overflow, if so just set the result to 0xFF.

Do you may have an idea how to implement this efficiently or do you have a better approach than the described one?

from micropython-i2s-examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.