Sound for model railroading scale 1/32

Status
Not open for further replies.

Benoit92

Well-known member
I have the project to built a DCC digital locomotive (see NmraDcc on Github).
For the command of electric motors and lights, the Arduino is enough without any problems.
But to sound the locos (electric, diesel or steam), I need more memories.
So, I have choosen the Teensy 3.2.

I start with the example :"SamplePlayer" https://github.com/PaulStoffregen/Audio/blob/master/examples/SamplePlayer/SamplePlayer.ino"
I removed all the instructions regarding the shield : AudioControlSGTL5000 audioShield or SD Shield

Obviously, I shall later change "AudioSampleSnare" by "Compressor release", "Horn", "Brake", . . . and sounds will be synchronized with speed, acceleration, deceleration or DCC commands for "Horn".

But, I got the following message on IDE Arduino:
C:\Documents\Arduino\PlayFromSketchV0\PlayFromSketchV0.ino:13:92: fatal error: AudioSampleSnare.h: No such file or directory
compilation terminated.


SamplePlayer.ino
Code:
#include <output_dac.h>
#include <play_memory.h>
#include <Audio.h>


// WAV files converted to code by wav2sketch
#include "AudioSampleSnare.h"        // http://www.freesound.org/people/KEVOY/sounds/82583/

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
AudioPlayMemory    sound0;
AudioOutputAnalog  dac;     // play to both I2S audio board and on-chip DAC

// Create Audio connections between the components
//
AudioConnection c1(sound0,dac);

void setup() {

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(10);
  analogWriteResolution(12);

  // turn on the output
//  audioShield.enable();
//  audioShield.volume(50);

  // by default the Teensy 3.1 DAC uses 3.3Vp-p output
  // if your 3.3V power has noise, switching to the
  // internal 1.2V reference can give you a clean signal
  //dac.analogReference(INTERNAL);

}

void loop() {
   sound0.play(AudioSampleSnare);

}

AudioSampleSnare.cpp
Code:
// Audio data converted from WAV file by wav2sketch
// Converted from AudioSampleSnare.wav, using 22050 Hz, u-law encoding

const unsigned int AudioSampleSnare [2817] = {
0x02002BD3,0x65636656,0x6B6A6B67,0x7071706F,0x43637171,0x29ABBA23,0x3137474C,0x3A4A544D,
0x30C1542C,0xE14F6360,0xEDDCE2E6, ............................................
};

AudioSampleSnare.h
Code:
// Audio data converted from WAV file by wav2sketch
extern const unsigned int AudioSampleSnare[2817];
Thanks
 
Does the file name match? #include "AudioSampleSnare.h"
That is, is your AudioSampleSnare.h file named exactly the same? Including the case of the characters?

I am assuming windows, as the error message: C:\Documents\Arduino\PlayFromSketchV0\PlayFromSket chV0.ino

And windows file system is not case sensitive, but I have have seen where some of the Arduino compile and preprocessor tools are case sensitive.
 
I don't understand because, when I place :
Code:
const unsigned int AudioSampleSnare [2817] = {
0x02002BD3,0x65636656,0x6B6A6B67,0x7071706F,0x43637171,0x29ABBA23,0x3137474C,0x3A4A544D,
0x30C1542C,0xE14F6360,0xEDDCE2E6, ............................................
};
int he *.ino --> no problem

and when I dispatche the "const unsigned int AudioSampleSnare [2817]" in *.h and *.cpp (all are in the same directory than *.ino),
there is the following message error :
C:\Users\AppData\Local\Temp\arduino_build_592557\sketch\PlayFromSketchVZ2.ino.cpp.o: In function `loop':
C:\Users\Documents\PlayFromSketchVZ2/PlayFromSketchVZ2.ino:381: undefined reference to `Toto'
collect2.exe: error: ld returned 1 exit status
Erreur de compilation pour la carte Teensy 3.2 / 3.1
 
Hard for me to say, without seeing the full sources. Like what is at line 381? Maybe create a zip file of the sketch and upload it as an attachment. I believe you can use the tools->Archive Sketch menu item to create the zip file.
 
Thank you, now, it's Ok.
In fact, I have choosen a Teensy 3.2 due to memory capacity (in comparaison with Arduino)
But, with Arduino, I can encode *.wav in 8 bits / 11025 Hz
and with Teensy Wav2sketch 16 bits mono / 44,xxxxx kHz.
So, I got too big file and I loose real advantages in term of duration (I don't need high quality sound).

1) Is it possible to encode sound on Teensy with only 8 bits mono / 11025 Hz ?
2) Is it possible to avoid to get "click" each time I begin the "loop" again ? low-pass filter ? teensy 3.5 with SDcard ? ...........

Nota :
The teensy receives every time a NMRADCC packets which give speed command, acceleration and décéleration.
The NMRADCC process needs to be integrated in the "loop" part of the programm.

Thanks
 
1) Is it possible to encode sound on Teensy with only 8 bits mono / 11025 Hz ?

Yes.

Just convert the WAV file to 11025 Hz, using Audacity or any other sound editing software. I highly recommend re-opening the WAV file and listening to it from your PC. Not all sound editing software is created equal. Some programs don't do the conversion properly unless extra options are used.

When you run wav2sketch, it preserves the 16 bit resolution if you give it "-16" on the command line. Otherwise it converts to 8 bit u-law encoded.

The memory-based sample playing code on Teensy supports 6 formats, 11025, 21050 and 44110 Hz sample rate, at either 16 bit or 8 bit u-law. If you're not familiar with u-law, in a nutshell it uses non-linear scaling (similar to human hearing sensitivity) for the 8 bits, so you get the dynamic range and noise floor of ~12 bits. But the trade-off is some distortion added, especially intermodulation distortion if your clip is composed of multiple sounds mixed together. Generally u-law works well for single voices and single sound effects, but performs poorly for musical compositions.

The memory sound clips are always mono. The wav2sketch automatically converts stereo to mono. The only way to get stereo is with 2 players and 2 clips.


2) Is it possible to avoid to get "click" each time I begin the "loop" again ? low-pass filter ? teensy 3.5 with SDcard ? ...........

Nobody can say, without knowing the details of what you're really doing.

But if I had to guess, I'd go with yes, clicks are almost always avoidable. Without actually fixing whatever is wrong with the data, a common way to solve click involves using the envelope or fade objects.
 
Thank you for your explanation.

From Audacity, I export in some formats and I got the following results :

1) 16 bits : initial wav 198 Ko after wav2sketch.exe -> 278 Ko (Ok, but why such inflation ?)

2) 8 bits unsigned : initial wav 99Ko after wav2sketch.exe-> error :(
converting: Steam_8_unsign.wav --> AudioSampleSteam_8_unsign
wav2sketch: file Steam_8_unsign.wav has 8 bit format, but only 16 is supported

3) u_law : initial wav 99Ko after wav2sketch.exe-> error :(
converting: Steam_starting_u_law.wav --> AudioSampleSteam_starting_u_law
wav2sketch: error in format of file Steam_starting_u_law.wav
 
(Ok, but why such inflation ?)

Maybe you're comparing the .WAV file size to the .CPP file size? WAV is efficiently packed binary data. CPP is ascii text. You can view the file in Arduino (just click on its tab) and clearly see the data for each 4 bytes of memory is stored as 9 characters of ASCII text, plus newlines chars after each line.

The number which matters on Teensy is the change in "Sketch uses 54812 bytes (20%) of program storage space."
 
Does it existe, on Teensy, a programm wich can use soundfile converted with "EncoderAudio" (8 bits/8kHz - It's enough for my application) and which uses PWM pin ?
I think that 2 timers would be changed through the library : #include <PCM.h>.
From Arduino forum :
* Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
* For Arduino with Atmega168 at 16 MHz.
*
* Uses two timers. The first changes the sample value 8000 times a second.
* The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
* depending on sample value. The second timer repeats 62500 times per second
* (16000000 / 256), much faster than the playback rate (8000 Hz), so
* it almost sounds halfway decent, just really quiet on a PC speaker.
*
* Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
* (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
* for the pulse width modulation, breaking PWM for pins 11 & 3.
 
You could pretty easily make such a program, since 8 kHz is so very slow. Just use IntervalTimer to run a function that reads the next byte and do analogWrite. Also use analogWriteFrequency in setup() so the frequency is higher. Details here:

IntervalTimer:
https://www.pjrc.com/teensy/td_timing_IntervalTimer.html

analogWriteFrequency:
https://www.pjrc.com/teensy/td_pulse.html

You could also get much better help here with the click problem and other issues if you post complete code. When you hold back on code and details, everyone is really limited in how much we can help.
 
Thank you for these advices.
Nota :I am a very young beginner in software (I am 60 years old but not in retirement) !
 
It's Ok to generate sound.
I have now to integrate sound generation in the NmraDcc code which was developed for Arduino.
In this case, Arduino uses Pin 2 (Int0) as external Interruption to receive packets signal from rails.
Can I use pin 2 (or others ??) on Teensy 3.2 to receive Dcc signal ?
Thanks
 
The recommended way to use pin interrupts is:

attachInterrupt(digitalPinToInterrupt(pin), function, mode);

You didn't post the link to the code in question (eg, the "Forum Rule") so we can't see whether it already has digitalPinToInterrupt, or if it has the number 0 or 1 which mean pins 2 or 3 on Arduino Uno. In fact, it's not really even clear if you mean Uno when you write "which was developed for Arduino", but that seems likely.

So, without details, the best I can suggest is use the recommended form with digitalPinToInterrupt. That works on all Arduino and all Teensy boards, as long as you use a pin which supports interrupts.

You should probably also be aware interrupts tend to be very sensitive if you use signals that have noise from the mechanical chatter of switches or other mechanical contacts. The faster the processor, the more sensitive it can be. Teensy 3.2 is much, much faster than most Arduino boards.
 
In the library NmraDcc on Github, there is the following function in NmraDcc.cpp :
Code:
NmraDcc::NmraDcc()
{
}

void NmraDcc::pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup)
{
#if defined ( __STM32F1__ )
  // with STM32F1 the interuptnumber is equal the pin number
  DccProcState.ExtIntNum = ExtIntPinNum;
#else
  DccProcState.ExtIntNum = ExtIntNum;
#endif
  DccProcState.ExtIntPinNum = ExtIntPinNum;
	
  pinMode( ExtIntPinNum, INPUT );
  if( EnablePullup )
    digitalWrite(ExtIntPinNum, HIGH);
}

In the application.ino, there is the following line to choose the pin (usually pin 2 - int0)?
Code:
   // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up 
Dcc.pin(0, 2, 0);
Does this method go with Teensy 3.2 ?
I am a beginner and I hope that I have describe my problem with enough clearness
 
Teensy 3.2 uses the same numbers for interrupts and pins. So pin 2 is interrupt 2 on Teensy 3.2.

Arduino Uno, the most popular Arduino board, has only 2 pins which support interrupts. It uses interrupt #0 for pin 2 and #1 for pin 3. Maybe you're seeing advice that was specific to Uno?

From only the code fragments shown, my guess (admittedly a bit of guesswork) is you would use Dcc.pin(2, 2, 0) or Dcc.pin(2, 2, 1), depending on whether your hradware has a real pullup resistor.


I hope that I have describe my problem with enough clearness

A link to the complete source for this library would have been much better.
 
Hello,
I try to use only one teensy 3.2 with SPI Flash 64 M to deal with all the functions (motor, lights and sound).
1) But, I wonder what is the signification of "0xF8A00" in "const unsigned int AudioSampleStandby = 0xF8A00;"
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <NmraDcc.h>
#include <Servo.h>
//#include <SD.h>
//#include <Bounce.h>
#include <play_serialflash.h>

//16 Bit RAW - Converted with wav2trw -16
const unsigned int AudioSampleStandby = 0xF8A00;          //TBD Length - AudioSampleStandby.raw
const unsigned int AudioSampleSteam = 0;                  //TBD Length - AudioSampleSteam.raw
const unsigned int AudioSampleCompressor = 0xD0B00;       //TBD Length - AudioSampleCompressor.raw
const unsigned int AudioSampleAirRelease =  0xDCD00;      //TBD Length - AudioSampleAirRelease.raw
const unsigned int AudioSampleBell = 0x9500;              //TBD Length - AudioSampleBell.raw
const unsigned int AudioSampleWhistle = 0xE2100;          //TBD Length - AudioSampleWhistle.raw
const unsigned int AudioSampleShoveling = 0xE2100;        //TBD Length - AudioSampleShoveling.raw

2) In order to write Soundfiles on SPI Flash, I shall use "rawfile-uploader.py" ??? but where I have to place the Soundfiles in my PC.

Thanks.
 
Hi, I am trying to load rawsoundfile (AABR99.trw) from PC (ASUS 550C - Windows10) to Spi Flash Memory (25Q64BVSIG) with a teensy 3.2.
Memory <-> Teensy connection
WP/IO2......................none
DO/IO1 (MISO).......... pin 12
HOLD/IO3...................3,3 V
DI/IO0 (MOSI).............pin7
CS............................pin6
CLK...........................pin14
VCC..........................3,3 V

CopyFromSerial
I just changed (no Audio board):
Code:
//SPI Pins (these are the values on the Audio board; change them if you have different ones)
//#define MOSI               7
//#define MISO              12
//#define SCK               14 
#define CSPIN              6
//#define CSPIN           21  // Arduino 101 built-in SPI Flash

void setup(){
  Serial.begin(9600);  //Teensy serial is always at full USB speed and buffered... the baud rate here is required but ignored


  pinMode(13, OUTPUT);
   
//  Set up SPI Teensy without audio Card
  SPI.setMOSI(7);  // uncomment these if using the alternate pins
  SPI.setMISO(12);
  SPI.setSCK(14);
Raw-uploader.py (Python 2.7)
No change.

Results on windows command prompt :
C:\Python27>python "rawfile-uploader.py" "com4" "AABR99.trw"
Uploading 1 files...
1: AABR99.trwTraceback (most recent call last):
File "rawfile-uploader.py", line 80, in <module>
ser.write("".join(encoded))
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 295, in write
raise writeTimeoutError
serial.serialutil.SerialTimeoutException: Write timeout

On Teensy, Led 13 toggles at 1Hz rate.
I wonder if the problem comes from Windows or from another causes.
Thanks.
 
Hi,
My configuration is
Teensy 3.2 + SPI Flash Winbond 25Q64BVSIG (without audioshield)
Pins used are 11(DOUT),12(DIN),14(SCK),10(CS).
One File.trw has been loaded in the SPI Flash.

In order to read the File and send it to DAC, do I need the following data (blacken number)?
EG:
const unsigned int AudioSampleSnare = 0xF8A00; //82583__kevoy__snare-drum-4.raw
const unsigned int AudioSampleTomtom = 0; //86334__zgump__tom-0104.raw
const unsigned int AudioSampleHihat = 0xD0B00; //102790__mhc__acoustic-open-hihat2.raw
const unsigned int AudioSampleKick = 0xDCD00; //171104__dwsd__kick-gettinglaid.raw
const unsigned int AudioSampleGong = 0x9500

If yes, how can I get these data ?
Thanks.
 
Hi,
My configuration is
Teensy 3.2 + SPI Flash Winbond 25Q64BVSIG (without audioshield)
Pins used are 11(DOUT),12(DIN),14(SCK),10(CS).
AR2BR99.TRW has been loaded in the SPI Flash.
I would like to send this file to the DAC (A14).
But, there is no sound.
Do I forget something ?
Thanks

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

#define FLASH_CHIP_SELECT 10
  
// GUItool: begin automatically generated code
AudioPlaySerialflashRaw  playFlashRaw1;  //xy=114,184
AudioOutputAnalog        dac1;           //xy=751,337
AudioConnection          patchCord1(playFlashRaw1, dac1);
// GUItool: end automatically generated code

void setup() {
  AudioMemory(10);
  analogReference(EXTERNAL);
//************************************
//  Set up SPI Teensy without audio Card
  SPI.setMOSI(11); 
  SPI.setMISO(12);
  SPI.setSCK(14);
//************************************
    Serial.begin(9600);
    while (!Serial) ;
    delay(100);
    
    if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
        while (1){
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
        }
      }

   playFile("AR2BR99.TRW");
   delay(20000);
}
      void playFile(const char *filename){
        Serial.print("Playing file: ");
        Serial.println(filename);
        // Start playing the file. This sketch continues to
        // run while the file plays.
        playFlashRaw1.play("AR2BR99.TRW");
        delay(20000);
       }    
void loop() {

}
 
I have the impression that it should not be possible (without audio card) to output the sound from the SPI Flash directly to the Teensy DAC (pin A14) by using "playFlashRaw1.play(filename).

On the PRJC website: https://www.pjrc.com/store/teensy3_audio.html, the Teensy is coupled to an audio card which has an SD player and a slot for soldering a Flash SPI.
This card has in particular a DAC which must be implemented thanks to the Audio.h library (PlayFlashRaw).
The Teensy drives the audio card via an I2C bus (SDA - SCL) and the serial bus (Tx - Rx).
It seems that the PlayRawFlash library can only implement the DAC of the audio card (but not the Teensy DAC).
Is there a possibility to output the sound of the SPI Flash to the Teensy DAC (A14 output)?
 
Status
Not open for further replies.
Back
Top