Pitch changing for audio playback application

Status
Not open for further replies.

Sandro

Well-known member
Hi all! I'd like to make a simple sampler/player based on Teensy; anyone knows if it's possible to change the pitch when playing an audio sample?
Thanks!
 
I've found at least one post about this topic. Apparently ... it seems an easy task stretching or shortening a waveform from samples, if only there is time for some simple interpolations:
[ATTACH = CONFIG] 13275 [/ ATTACH]
I'm sure I'm saying banality ... For sure things are more complex than I belive... :rolleyes:
Thanks
Sandro
 

Attachments

  • SAMPLER.jpg
    SAMPLER.jpg
    46.1 KB · Views: 177
Read the GUI synth section,some extracts copied below....

begin(waveform);
Configure the waveform type to create.

begin(level, frequency, waveform);
Output a waveform, and set the amplitude and frequency.

frequency(freq);
Change the frequency

...........
 
Hi Teenfor3,
thank you for your answer; I need to use one "play" item (playFlashRaw) not a synth item, because I want to play audio samples. I did some search on internet, the topic of pitch shifting seems so difficult... Just one hour ago found this paper from Iowa State University:
dec1712.sd.ece.iastate.edu/uploads/1/0/3/1/103197054/wr_10_1712.pdf
It says that in Iowa State University, professors Geiger and Chen and their students are (were) working on a "pitch shifting effect for the Teensy"... Maybe something new is coming?
Bye!
Sandro
 
Your first post showed waveforms of what looks like 1 cycle sample, so play it at what ever pitch you want using the procs in my earlier post.
Wavforms like this can be extracted from any wav file sample.

You would need to explain what you are trying to do, size of samples...??? Play once through and stop or play repeated...??

must the processing be done on teensy or can sample be pre-process on other software for teensy to play..???

etc...etc.....
 
Hi Teenfor3, I posted that waveform with the purpose to show how I intend the pitch changing, but maybe was misleading, sorry, because my sample is a .wav file containing a speech, or a piece of a song, or some noise, it is not periodic wave.
What I want to make is an expander with a sinlge sample inside: would store one .wav file in W25Q128FV serial flash memoery, attach a midi keyboard to the Teensy with a simple Midi-in interface, and play the .wav at different pitch/speed, depending on the note number; and eventually use the pitch bend control of the keyboard. All this would be easy, I think, if AudioPlaySerialFlashRaw had a "pitch" function..
Thanks a lot
Sandro
 
Don't know much about expanders but the W25Q128FV has option 8.2.6 Read Data 03h in the datasheet to read continuously from memory location and can use variable clock to control rate so maybe this could be used.......similar to "old" audio projects where a counter was used to count up and overflow to scan and read out the total memory space sequentially.
 
I don't doubt that the solution you propose is working good. With this "hardware" approach, I belive there would be advantages (semplicity of sw design) but also shortcoming, the worst is that we would give up the awsome poliphony allowed by AudioPlaySerialFlashRaw function using one single W25Q128FV chip ... Poliphony would be obtained by putting toghether many W25Q128FV, one for each voice.. I really prefer a "software" approach, as long as it is possible. I will annoy professors Geiger and Chen, hopeing they are close to a solution!! :)
Thank you
 
Dynamically adjust pitch of WAV audio

Take a look here:
https://forum.pjrc.com/threads/46793-Anyone-Doing-Pitch-Shifting

I also wrote some code using this technique. I'll see if I can dig it up.

I would be very interested in a solution for this. Here's my use case: I am building a sub simulator for my 9 year old:

https://developer.ibm.com/recipes/tutorials/iot-submarine-simulator/

I took a rough approach to simulating the engines revving up/down: I edited a wav sample of an engine and did a pitch change in adobe audition. I end up with 10+ WAV files which I play out depending on the speed of the boat. However there are problems with this - if I use very short wav files I end up with a lot of audio clipping between replays of the sample files. I gues I could load the right audio file into memory and play from there. I am curious if I can do a pitch change of a single sample file and adjust the pitch as desired.

Tiran
 
Tiran wrote " I am curious if I can do a pitch change of a single sample file and adjust the pitch as desired."

Yes, Arbitrary Waveform, play sample at what ever frequency, duration and amplitude you want, see the teensy audio examples and the GUI design tool
 
Pitch changing for audio playback

Tiran wrote " I am curious if I can do a pitch change of a single sample file and adjust the pitch as desired."

Yes, Arbitrary Waveform, play sample at what ever frequency, duration and amplitude you want, see the teensy audio examples and the GUI design tool


Teenfor3 thank you for replying. I looked at the tutorial and most of the examples (pouring through them) and could not find an example where an audio wav file is played at a different pitch than its original form. Can you point it out to me or share a link or page number? I have seen people try this on the teensy audio library by suggesting it requires a custom filter library but have not seen working code examples. See this thread:

https://forum.pjrc.com/threads/26767-Teensy-3-0-3-1-Audio-Library-with-sound-pitch-control
 
Probably not much simpler than this. This is a sample from Audacity export sample data as text from wav file and play in teensy using interval timer. the rate in the sketch is varied by counting down a timer but could be controlled by buttons or pot also the loudness or amplitude could also be controlled.
 

Attachments

  • engine.h
    7.9 KB · Views: 175
  • Simple_DACengine.ino
    548 bytes · Views: 173
Teenfor3:

I love the simplicity of your approach. Unfortunately I am doing this using the Audio library and the Audio card. I need to output through the card and have 2-3 other audio track playing. For instance the engine might be revved up high because we are in pursuit and a torpedo sound fires while the captain announces "we are at full speed!". I need the pitch modulation to occur within the audio library for the PJRC audio card therefor...
 
Teenfor3:

I love the simplicity of your approach. Unfortunately I am doing this using the Audio library and the Audio card. I need to output through the card and have 2-3 other audio track playing. For instance the engine might be revved up high because we are in pursuit and a torpedo sound fires while the captain announces "we are at full speed!". I need the pitch modulation to occur within the audio library for the PJRC audio card therefor...

Moving my thread to a different thread:
https://forum.pjrc.com/threads/50712-Audio-Board-Problems-intermittent-pauses?p=174033#post174033
 
Dears, I'm trying to add a function "pitch" to playFlashRaw; of course I will fail, but I'll try, with the goal of learning at least something about C++ and Teensy.

So... first, if someone is so patient to explain me, in this (I belive) crucial part of code: I understand that we read AUDIO_BLOCK_SAMPLES*2 samples and then we delete half of them.. I'm wrong? :eek:

Code:
if (rawfile.available()) {
		// we can read more data from the file...
		n = rawfile.read(block->data, AUDIO_BLOCK_SAMPLES*2);
		file_offset += n;
		for (i=n/2; i < AUDIO_BLOCK_SAMPLES; i++) {
			block->data[i] = 0;
		}
		transmit(block);
}
 
Hi all,
I'm trying to modify play_serialflash_raw.cpp in order to add the pitch functionality; I've developed a simple demo with fixed pitch 50% (the sample is played at half speed) just to check if I'm on a good road. This is the code (my insertion/modification are evidenced with comments starting with // ****** ):

Code:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 * Modified to use SerialFlash instead of SD library by Wyatt Olson <wyatt@digitalcave.ca>
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "play_serialflash_raw.h"
#include "spi_interrupt.h"

int16_t ride;   // ****** number of time update is called
int16_t box[128]; // ****** sound samples, local vector
int16_t first_sample; // ****** each ride, the last sample read is stored here
unsigned long t, t_0; // ***** computational time, must be within 2500 micros

void AudioPlaySerialflashRaw::begin(void)
{
	playing = false;
	file_offset = 0;
	file_size = 0;
}


bool AudioPlaySerialflashRaw::play(const char *filename)
{
	stop();
	ride=0; // ***** my code
	AudioStartUsingSPI();
	rawfile = SerialFlash.open(filename);
	if (!rawfile) {
		//Serial.println("unable to open file");
		AudioStopUsingSPI();
		return false;
	}
	file_size = rawfile.size();
	file_offset = 0;
	//Serial.println("able to open file");
	playing = true;
	return true;
}

void AudioPlaySerialflashRaw::stop(void)
{
	__disable_irq();
	if (playing) {
		playing = false;
		__enable_irq();
		rawfile.close();
		AudioStopUsingSPI();
	} else {
		__enable_irq();
	}
}


void AudioPlaySerialflashRaw::update(void)
{
	
	int16_t b[128]; // ******* temporay vector used to store caluculated values
	unsigned int h, k; // ***** my code
	
	unsigned int i, n;	
	audio_block_t *block;
    
	// only update if we're playing
	if (!playing) return;

	// allocate the audio blocks to transmit
	block = allocate();
	if (block == NULL) return;

	if (rawfile.available()) {
		
        // ***** my code starts...
	    t_0=micros(); // ***** checking the computational time, must be within 2500 micros
		
		if (ride==0) {
		// we can read more data from the file...
		n = rawfile.read(block->data, 65*2); // ***** only for the first ride 65 samples are needed
		file_offset += n;
			for (i=n/2; i < 65; i++) {
			block->data[i] = 0;
			}	
			for (i=0;i<128;i++) {
				h=(floor((float)i/2.0)); // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0));	 // ***** upper sample needed for calculation
				b[i]=(block->data[h]+block->data[k])/2; // **** interpolated value
			}
            first_sample=block->data[64]; // ***** last sample read from file will be used in the next ride
		}
		
		else {
		// we can read more data from the file...
		n = rawfile.read(block->data, 64*2); // ***** from the second ride 64 samples are needed (the first comes from the previous ride)
		file_offset += n;
		for (i=n/2; i < 64; i++) {
			block->data[i] = 0;
		}	
			b[0]=first_sample;
			for (i=1;i<128;i++) {
				h=(floor((float)i/2.0)); // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0));	 // ***** upper sample needed for calculation
				b[i]=(block->data[h]+block->data[k])/2;	// **** interpolated value			
			}
            first_sample=block->data[63]; // ***** last sample read from file will be used in the next ride
		}
		
		for (i=0;i<128;i++) { // ***** preparing samples to be sent out
			block->data[i]=b[i];
		}	
		
			
		t=micros()-t_0; // ***** checking the computational time, must be within 2500 micros
		ride ++;		
		// ***** my code ends 

		transmit(block);
	}
	
	else {
		rawfile.close();
		AudioStopUsingSPI();
		playing = false;
		//Serial.println("Finished playing sample");		//TODO
	}
	release(block);
	
}

#define B2M (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT / 2.0) // 97352592

uint32_t AudioPlaySerialflashRaw::positionMillis(void)
{
	return ((uint64_t)file_offset * B2M) >> 32;
}

uint32_t AudioPlaySerialflashRaw::lengthMillis(void)
{
	return ((uint64_t)file_size * B2M) >> 32;
}


int AudioPlaySerialflashRaw::time_lapse(void) // // ***** reporting the computational time, must be within 2500 micros
{
	return t;
}

The result is half good, I can listen the sample with pitch 50% but ther are glitches.. maybe there are some gross mistakes? The computational time for calculating each new block of 128 samples is always <800 microseconds, this should be fine for the correct behave of the object... Can anybody have a look and help me to find what's wrong?
Thanks a lot!
 
Last edited:
I found one bug, a mistake with indexes... Now my demo behaves much better, this is the updated code:

Code:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 * Modified to use SerialFlash instead of SD library by Wyatt Olson <wyatt@digitalcave.ca>
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "play_serialflash_raw.h"
#include "spi_interrupt.h"

int16_t ride;   // ****** number of time update is called
int16_t box[128]; // ****** sound samples, local vector
int16_t first_sample; // ****** each ride, the last sample read is stored here
unsigned long t, t_0; // ***** t is the computational time, must be within 2500 microseconds

void AudioPlaySerialflashRaw::begin(void)
{
	playing = false;
	file_offset = 0;
	file_size = 0;
}


bool AudioPlaySerialflashRaw::play(const char *filename)
{
	stop();
	ride=0; // ***** my code
	AudioStartUsingSPI();
	rawfile = SerialFlash.open(filename);
	if (!rawfile) {
		//Serial.println("unable to open file");
		AudioStopUsingSPI();
		return false;
	}
	file_size = rawfile.size();
	file_offset = 0;
	//Serial.println("able to open file");
	playing = true;
	return true;
}

void AudioPlaySerialflashRaw::stop(void)
{
	__disable_irq();
	if (playing) {
		playing = false;
		__enable_irq();
		rawfile.close();
		AudioStopUsingSPI();
	} else {
		__enable_irq();
	}
}


void AudioPlaySerialflashRaw::update(void)
{
	
	int16_t b[128]; // ******* temporay vector used to store caluculated values
	unsigned int h, k; // ******* two variables used to stor indexes
	
	unsigned int i, n;	
	audio_block_t *block;
    
	// only update if we're playing
	if (!playing) return;

	// allocate the audio blocks to transmit
	block = allocate();
	if (block == NULL) return;

	if (rawfile.available()) {
		
        // ***** main code starts here
	    t_0=micros(); // ***** checking the computational time, must be within 2500 micros
		
		if (ride==0) {
		// we can read more data from the file...
		n = rawfile.read(block->data, 65*2); // ***** only for the first ride 65 samples are needed
		file_offset += n;
			for (i=n/2; i < 65; i++) {
			block->data[i] = 0;
			}	
			for (i=0;i<128;i++) {
				h=(floor((float)i/2.0)); // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0));	 // ***** upper sample needed for calculation
				b[i]=(block->data[h]+block->data[k])/2; // **** interpolated value
			}
            first_sample=block->data[64]; // ***** last sample read from file will be used in the next ride
		}
		
		else {
		// we can read more data from the file...
		n = rawfile.read(block->data, 64*2); // ***** from the second ride 64 samples are needed (the first comes from the previous ride)
		file_offset += n;
		for (i=n/2; i < 64; i++) {
			block->data[i] = 0;
		}	
			for (i=0;i<128;i++) {
				h=(floor((float)i/2.0))-1; // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0))-1;	 // ***** upper sample needed for calculation
				b[i]=(((h<0) ? first_sample: block->data[h])+((k<0)? first_sample: block->data[k]))/2;	// **** interpolated value
			}
            first_sample=block->data[63]; // ***** last sample read from file will be used in the next ride
		}

		for (i=0;i<128;i++) { // ***** preparing samples to be sent out
			block->data[i]=b[i];
		}	
		
		t=micros()-t_0; // ***** checking the computational time, must be within 2500 micros
		ride ++;		
		// ***** main code ends here

		transmit(block);
	}
	
	else {
		rawfile.close();
		AudioStopUsingSPI();
		playing = false;
		//Serial.println("Finished playing sample");		//TODO
	}
	release(block);
	
}

#define B2M (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT / 2.0) // 97352592

uint32_t AudioPlaySerialflashRaw::positionMillis(void)
{
	return ((uint64_t)file_offset * B2M) >> 32;
}

uint32_t AudioPlaySerialflashRaw::lengthMillis(void)
{
	return ((uint64_t)file_size * B2M) >> 32;
}


int AudioPlaySerialflashRaw::time_lapse(void) // // ***** reporting the computational time t, must be within 2500 microseconds
{
	return t;
}

Some spike noise is still present.. but with much lower volume than before.
 
Last edited:
Hi all, i found a gross mistake with 2 declarations! Now the demo is working fine, and the audio file stored in flash memory is played at 50% speed!
I'm proud to share this demo I wrote (needless to say that I'm a beginner, and my code is obviously "naive"... please forgive me!!):

Code:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 * Modified to use SerialFlash instead of SD library by Wyatt Olson <wyatt@digitalcave.ca>
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "play_serialflash_raw.h"
#include "spi_interrupt.h"

int16_t ride;   // ****** number of time update() is called
int16_t first_sample; // ****** each ride, the last sample read is stored here
unsigned long t, t_0; // ***** t is the computational time, must be within 2500 microseconds
int16_t bytes_read;   // ****** number of valid bytes read each update()


void AudioPlaySerialflashRaw::begin(void)
{
	playing = false;
	file_offset = 0;
	file_size = 0;
}


bool AudioPlaySerialflashRaw::play(const char *filename)
{
	stop();
	ride=0; // ***** my code
	AudioStartUsingSPI();
	rawfile = SerialFlash.open(filename);
	if (!rawfile) {
		//Serial.println("unable to open file");
		AudioStopUsingSPI();
		return false;
	}
	file_size = rawfile.size();
	file_offset = 0;
	//Serial.println("able to open file");
	playing = true;
	return true;
}

void AudioPlaySerialflashRaw::stop(void)
{
	__disable_irq();
	if (playing) {
		playing = false;
		__enable_irq();
		rawfile.close();
		AudioStopUsingSPI();
	} else {
		__enable_irq();
	}
}


void AudioPlaySerialflashRaw::update(void)
{
	
	int16_t b[128]; // ******* temporay vector used to store caluculated values
	int16_t h, k; // ******* two variables used to store indexes
	
	unsigned int i, n;	
	audio_block_t *block;
    
	// only update if we're playing
	if (!playing) return;

	// allocate the audio blocks to transmit
	block = allocate();
	if (block == NULL) return;

	if (rawfile.available()) {
		
        // ***** main code starts here
	    t_0=micros(); // ***** checking the computational time, must be within 2500 micros
		
		if (ride==0) {
		// we can read more data from the file...
		n = rawfile.read(block->data, 65*2); // ***** only for the first ride 65 samples are needed
		bytes_read=n;
		file_offset += n;
			for (i=n/2; i < 65; i++) {
			block->data[i] = 0;
			}	
			for (i=0;i<128;i++) {
				h=(floor((float)i/2.0)); // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0));	 // ***** upper sample needed for calculation
				b[i]=(block->data[h]+block->data[k])/2; // **** interpolated value
			}
            first_sample=block->data[64]; // ***** last sample read from file will be used in the next ride
		}
		
		else {
		// we can read more data from the file...
		n = rawfile.read(block->data, 64*2); // ***** from the second ride 64 samples are needed (the first comes from the previous ride)
		bytes_read=n;
		file_offset += n;
		for (i=n/2; i < 64; i++) {
			block->data[i] = 0;
		}	
			for (i=0;i<128;i++) {
				h=(floor((float)i/2.0))-1; // ***** lower sample needed for calculation 
				k=(ceil((float)i/2.0))-1;	 // ***** upper sample needed for calculation
				b[i]=(((h<0) ? first_sample: block->data[h])+((k<0)? first_sample: block->data[k]))/2;	// **** interpolated value
			}
            first_sample=block->data[63]; // ***** last sample read from file will be used in the next ride
		}

		for (i=0;i<128;i++) { // ***** preparing samples to be sent out
			block->data[i]=b[i];
		}	
		
		t=micros()-t_0; // ***** checking the computational time, must be within 2500 micros
		ride ++;		
		// ***** main code ends here

		transmit(block);
	}
	
	else {
		rawfile.close();
		AudioStopUsingSPI();
		playing = false;
		//Serial.println("Finished playing sample");		//TODO
	}
	release(block);
	
}

#define B2M (uint32_t)((double)4294967296000.0 / AUDIO_SAMPLE_RATE_EXACT / 2.0) // 97352592

uint32_t AudioPlaySerialflashRaw::positionMillis(void)
{
	return ((uint64_t)file_offset * B2M) >> 32;
}

uint32_t AudioPlaySerialflashRaw::lengthMillis(void)
{
	return ((uint64_t)file_size * B2M) >> 32;
}


int AudioPlaySerialflashRaw::time_lapse(void) // // ***** reporting the computational time t, must be within 2500 microseconds
{
	return t;
}

int AudioPlaySerialflashRaw::bytes(void) // // ***** reporting the numeber of bytes read, just for some verification
{
	return bytes_read;
}

Now it's time to create a generalized algorithm for different pitch values!
 
Hi everyone,

Thanks Sandro for digging into this problem!
Because I can't test with serial flash memory, I've translated your code for the play_sd_raw.cpp and .h files.
I've also added an externalised method called setPitch to dynamically adjust the pitch variable outside the play() method, implemented like this :
Code:
bool AudioPlaySdRawPitch::setPitch(float pitch_value)
{  
  pitch = pitch_value; // ***** set pitch value
  return true;
}

Good news, It work well with fixed pitch. But the problem I'm facing with now is when I try to adjust it the loop() with this method. My point is to create a "tape wooble varispeed" effect :

Code:
float tapeSpeed(float _speed, float _depth, float _lp) {

  if (_depth > 0.0) {

    static float ws   = 0.0;
    static uint8_t w8 = 128;

    w8 += random(3) - 1;
    ws += ( ( ( ( (float) w8 / 256.0 ) - 0.5 ) * _depth ) - ws ) * _lp;                                                            

    return ws + _speed;

  } else {
    
    return _speed;

  }
}

void loop() {
    myCustomPlayer.setPitch( tapeSpeed( 1.0, 0.1, 0.001 ) );
}

The values generated by the tapeSpeed() method = a float number that constantly drift a little up and a little down around 1.0.

This result in a gradually distorded sound that ends-up by a reboot of the teensy itself. So bad...

Your code looks interesting but I think it need a drastic optimisation in the way you do the thing. It's quite hard to debug for me right now. I'm not a very good C++ coder too but I can help you to bring this thing stable and implement the realtime changing pitch.

Can you clarify your algorithm approach?
The quality of the resampling is very good to my ears (at fixed speed). I've seen you dont use any windowing or FIR filtering approach during resampling, Thats why I'm curious about how you build the interpolation.

Cheerz
Q
 
Probably not much simpler than this. This is a sample from Audacity export sample data as text from wav file and play in teensy using interval timer. the rate in the sketch is varied by counting down a timer but could be controlled by buttons or pot also the loudness or amplitude could also be controlled.

Long time reader, first time poster. :)

I'm trying to accomplish the same thing and for my use case, slowing down all of the samples would work great! I don't see any files attached to your post though... any chance that you could repost it?
 
Status
Not open for further replies.
Back
Top