Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: How do I run Teensy with USB audio output on Linux?

  1. #1
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    4,071

    Question How do I run Teensy with USB audio output on Linux?

    I decided to add to my series of tests to do simple audio output to different devices (I already have DAC, DACS, Audio Shield, I2S, I2S2, and Prop Shield). So I cloned my source that does ToneSweep on both the right and left channels to target USB output. But when I start the program, it just hangs there. I suspect I need something on the Linux side that takes the sound and sends it to the speakers. What do I need to hear the sounds from the Teensy on the Linux side? I am running Fedora 33 at the moment.

    Here is the program. I've tried it on a Teensy 3.2, specifying the USB type to be either Audio or Serial+Midi+Audio:

    Code:
    /*
      Demo of the audio sweep function.
      The user specifies the amplitude,
      start and end frequencies (which can sweep up or down)
      and the length of time of the sweep.
    
      Modified to eliminate the audio shield, and use the Teensy to send output via
      USB to the PC.  */
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    
    // GUItool: begin automatically generated code (edited by meissner afterwards).
    AudioSynthToneSweep	tonesweep;		//xy=99,198
    AudioMixer4		mixer2;			//xy=280,253
    AudioMixer4		mixer1;			//xy=280,175
    AudioOutputUSB		usb1;			//xy=452,189
    
    AudioConnection		patchCord1 (tonesweep, 0, mixer1, 0);
    AudioConnection		patchCord2 (tonesweep, 0, mixer2, 0);
    AudioConnection		patchCord3 (mixer2,    0, usb1,   1);
    AudioConnection		patchCord4 (mixer1,    0, usb1,   0);
    // GUItool: end automatically generated code
    
    const float	t_ampx	= 0.8;
    const int	t_lox	= 10;
    const int	t_hix	= 22000;
    const float	t_timex	= 10;		// Length of time for the sweep in seconds
    
    // Do a sweep in both directions, enabling or disabling the left/right speakers
    void do_sweep (int i)
    {
      int do_left  = (i & 1) != 0;
      int do_right = (i & 2) != 0;
      float gain   = (do_left && do_right) ? 0.5f : 1.0f;
    
      Serial.printf ("Sweep up,   left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      mixer1.gain (0, do_left  ? gain : 0.0f);
      mixer2.gain (0, do_right ? gain : 0.0f);
    
      if (!tonesweep.play (t_ampx, t_lox, t_hix, t_timex)) {
        Serial.println ("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep.isPlaying ())
        ;
    
      // and now reverse the sweep
      Serial.printf ("Sweep down, left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      if (!tonesweep.play (t_ampx, t_hix, t_lox, t_timex)) {
        Serial.println("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep.isPlaying ())
        ;
    
      Serial.println ("Sweep done");
    }
    
    void setup(void)
    {
      // Wait for at least 3 seconds for the USB serial connection
      Serial.begin (9600);
      while (!Serial && millis () < 3000)
        ;
    
      AudioMemory (8);
      Serial.println ("setup done");
    
      for (int i = 1; i <= 3; i++)
        do_sweep (i);
    
      Serial.println ("Done");
    }
    
    void loop (void)
    {
    }
    Last edited by MichaelMeissner; 04-19-2021 at 02:20 AM.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,452
    You need to have at least one non-USB input or output object. USB can't cause the audio library to update. Just add an I2S input or output, even if it's unused.

    This detail is documented in the "Notes" on the design tool for the USB output, but it's easy to miss.

    https://www.pjrc.com/teensy/gui/?info=AudioOutputUSB

  3. #3
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    4,071
    I thought having Tonesweep would be enough to pull in the Audio USB to the loop. But I put in a dummy I2S input -> mixer -> I2S output just to be sure.

    If I open up the Sound launcher in my menubar, and go to input, and select the Teensy input, I can see a bar graph as tonesweep is running. What I suspect I am missing is a Linux app that reads the sound from the USB stream and puts it on the speakers/headphones.

    Code:
    /*
      Demo of the audio sweep function.
      The user specifies the amplitude,
      start and end frequencies (which can sweep up or down)
      and the length of time of the sweep.
    
      Modified to eliminate the audio shield, and use the Teensy to send output via
      USB to the PC.  */
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code (edited by meissner afterwards).
    // I2S1/I2S2 are needed to make USB output work (you need at least one
    // definition of a non-USB audio event to trigger the main loop).
    AudioSynthToneSweep      tonesweep1;     //xy=151.90362548828125,302.89676666259766
    AudioInputI2S            i2s1;           //xy=151.90363311767578,541.8967809677124
    AudioMixer4              mixer1;         //xy=361.9036407470703,318.89673614501953
    AudioMixer4              mixer2;         //xy=368.9036636352539,435.8967514038086
    AudioMixer4              mixer3;         //xy=373.90362548828125,535.8967666625977
    AudioOutputUSB           usb1;           //xy=536.9036159515381,300.89677143096924
    AudioOutputI2S           i2s2;           //xy=543.9036254882812,525.8967666625977
    AudioConnection          patchCord1(tonesweep1, 0, mixer1, 0);
    AudioConnection          patchCord2(tonesweep1, 0, mixer2, 0);
    AudioConnection          patchCord3(i2s1, 0, mixer3, 0);
    AudioConnection          patchCord4(mixer1, 0, usb1, 0);
    AudioConnection          patchCord5(mixer2, 0, usb1, 1);
    AudioConnection          patchCord6(mixer3, 0, i2s2, 0);
    // GUItool: end automatically generated code
    
    const float	t_ampx	= 0.8;
    const int	t_lox	= 10;
    const int	t_hix	= 22000;
    const float	t_timex	= 10;		// Length of time for the sweep in seconds
    
    // Do a sweep in both directions, enabling or disabling the left/right speakers
    void do_sweep (int i)
    {
      int do_left  = (i & 1) != 0;
      int do_right = (i & 2) != 0;
      float gain   = (do_left && do_right) ? 0.5f : 1.0f;
    
      Serial.printf ("Sweep up,   left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      mixer1.gain (0, do_left  ? gain : 0.0f);
      mixer2.gain (0, do_right ? gain : 0.0f);
    
      // I2S fake input/output
      mixer3.gain (0, 0.0f);
    
      if (!tonesweep1.play (t_ampx, t_lox, t_hix, t_timex)) {
        Serial.println ("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep1.isPlaying ())
        ;
    
      // and now reverse the sweep
      Serial.printf ("Sweep down, left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      if (!tonesweep1.play (t_ampx, t_hix, t_lox, t_timex)) {
        Serial.println("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep1.isPlaying ())
        ;
    
      Serial.println ("Sweep done");
    }
    
    void setup(void)
    {
      // Wait for at least 3 seconds for the USB serial connection
      Serial.begin (9600);
      while (!Serial && millis () < 3000)
        ;
    
      AudioMemory (8);
      Serial.println ("setup done");
    
      for (int i = 1; i <= 3; i++)
        do_sweep (i);
    
      Serial.println ("Done");
    }
    
    void loop (void)
    {
    }

  4. #4
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    419
    something like alsa mixer (was years since since I played with Linux audio)

  5. #5
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    4,071
    Quote Originally Posted by mlu View Post
    something like alsa mixer (was years since since I played with Linux audio)
    That jogged my memory. I wasn't able to get alsa mixer to play (I could use F6 to change the stream to the Teensy, but I didn't hear a sound).

    But if I go into the sound preferences app from my menubar, I can change the default input to be the Teensy. Then if I use the command line program:
    • play -d


    It plays the sounds fine.

    And FWIW, Tonesweep is considered an audio output generator, so I didn't need to declare an I2S input device, but I left it in the program.

    Here is the final sketch:

    Code:
    // Demo of the audio sweep function.  The user specifies the amplitude, start
    // and end frequencies (which can sweep up or down) and the length of time of
    // the sweep.
    //
    // Modified to eliminate the audio shield, and use the Teensy to send output
    // via USB to the PC.
    //
    // To play this on a Linux system, after starting the application the first time
    // go into the sound preferences application on the menubar, and select the
    // Teensy as the default input device.  Then from the command line issue:
    //
    //	play -d
    //
    // When building this sketch, you need to set the USB type to either:
    //	Audio			(or)
    //	Serial + MIDI + Audio
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code (edited by meissner afterwards).
    // I2S1/I2S2 are needed to make USB output work (you need at least one
    // definition of a non-USB audio event to trigger the main loop).
    AudioSynthToneSweep      tonesweep1;     //xy=151.90362548828125,302.89676666259766
    AudioInputI2S            i2s1;           //xy=151.90363311767578,541.8967809677124
    AudioMixer4              mixer1;         //xy=361.9036407470703,318.89673614501953
    AudioMixer4              mixer2;         //xy=368.9036636352539,435.8967514038086
    AudioMixer4              mixer3;         //xy=373.90362548828125,535.8967666625977
    AudioOutputUSB           usb1;           //xy=536.9036159515381,300.89677143096924
    AudioOutputI2S           i2s2;           //xy=543.9036254882812,525.8967666625977
    AudioConnection          patchCord1(tonesweep1, 0, mixer1, 0);
    AudioConnection          patchCord2(tonesweep1, 0, mixer2, 0);
    AudioConnection          patchCord4(mixer1, 0, usb1, 0);
    AudioConnection          patchCord5(mixer2, 0, usb1, 1);
    AudioConnection          patchCord6(mixer3, 0, i2s2, 0);
    // GUItool: end automatically generated code
    
    const float	t_ampx	= 0.8;
    const int	t_lox	= 10;
    const int	t_hix	= 22000;
    const float	t_timex	= 10;		// Length of time for the sweep in seconds
    
    // Do a sweep in both directions, enabling or disabling the left/right speakers
    void do_sweep (int i)
    {
      int do_left  = (i & 1) != 0;
      int do_right = (i & 2) != 0;
      float gain   = (do_left && do_right) ? 0.5f : 1.0f;
    
      Serial.printf ("Sweep up,   left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      mixer1.gain (0, do_left  ? gain : 0.0f);
      mixer2.gain (0, do_right ? gain : 0.0f);
    
      if (!tonesweep1.play (t_ampx, t_lox, t_hix, t_timex)) {
        Serial.println ("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep1.isPlaying ())
        ;
    
      // and now reverse the sweep
      Serial.printf ("Sweep down, left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      if (!tonesweep1.play (t_ampx, t_hix, t_lox, t_timex)) {
        Serial.println("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep1.isPlaying ())
        ;
    
      Serial.println ("Sweep done");
    }
    
    void setup(void)
    {
      // Wait for at least 3 seconds for the USB serial connection
      Serial.begin (9600);
      while (!Serial && millis () < 3000)
        ;
    
      AudioMemory (8);
      Serial.println ("setup done");
    
      for (int i = 1; i <= 3; i++)
        do_sweep (i);
    
      Serial.println ("Done");
    }
    
    void loop (void)
    {
    }

  6. #6
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,631
    Quote Originally Posted by MichaelMeissner View Post
    That jogged my memory. I wasn't able to get alsa mixer to play (I could use F6 to change the stream to the Teensy, but I didn't hear a sound).

    But if I go into the sound preferences app from my menubar, I can change the default input to be the Teensy. Then if I use the command line program:

    play -d
    Ah, many thanks. For the last few years I've wondered why I couldn't get teensy-USB audio to play on my Ubuntu boxes. Now all is good.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •