title: Signed 16-bit ALSA PCM data to U8 Conversion on Linux
body: <p>I'm attempting to convert 16-bit ALSA PCM Samples to Unsigned 8-bit PCM samples for wireless transmission on Linux. The receiving machine is playing the transmitted data successfully and the recorded voice is there and recognizable, but the quality is terrible and noisy. I've tried ALSA mixer on both ends to tune the stream but it doesn't seem to get much better with that. I believe there is something wrong with my conversion of the samples to 8-bit PCM but its just a simple shift so I'm not sure what could be the error. Does anyone have any suggestions or see anything wrong with my conversion code? Thanks.</p>
  
  <p>Conversion Code:</p>
  
  <pre><code>            // This byte array needs to be the packet size we wish to send
              QByteArray prepareToSend;
              prepareToSend.clear();
  
              // Keep reading from ALSA until we fill one full frame
              int frames = 1;
              while ( prepareToSend.size() &lt; TARGET_TX_BUFFER_SIZE ) {
  
                  // Create a ByteArray
                  QByteArray readBytes;
                  readBytes.resize(size);
  
                  // Read with ALSA
                  short sample[1]; // Data is signed 16-bit
                  int rc = snd_pcm_readi(m_PlaybackHandle, sample, frames);
                  if (rc == -EPIPE) {
                      /* EPIPE means overrun */
                      fprintf(stderr, "Overrun occurred\n");
                      snd_pcm_prepare(m_PlaybackHandle);
                  } else if (rc &lt; 0) {
                      fprintf(stderr,
                              "Error from read: %s\n",
                              snd_strerror(rc));
                  } else if (rc != (int)frames) {
                      fprintf(stderr, "Short read, read %d frames\n", rc);
                  }
                  else {
                      // Copy bytes to the prepare to send buffer
                      //qDebug() &lt;&lt; "Bytes for sample buffer: " &lt;&lt; sizeof(sample);
                      prepareToSend.append((qint16)(sample[0]) &gt;&gt; 8); // signed 16-bit becomes u8
                  }
  
              }
  </code></pre>
  
  <p>ALSA Configuration:</p>
  
  <pre><code>        // Setup parameters
          int size;
          snd_pcm_t *m_PlaybackHandle;
          snd_pcm_hw_params_t *m_HwParams;
          char *buffer;
  
          qDebug() &lt;&lt; "Desire to Transmit Data - Setting up ALSA Now....";
  
          // Error handling
          int err;
  
          // Device to Write to
          const char *snd_device_in = "hw:1,0";
  
          if ((err = snd_pcm_open (&amp;m_PlaybackHandle, snd_device_in, SND_PCM_STREAM_CAPTURE, 0)) &lt; 0) {
              fprintf (stderr, "Cannot open audio device %s (%s)\n",
                       snd_device_in,
                       snd_strerror (err));
              exit (1);
          }
  
          /* Allocate a hardware parameters object. */
          snd_pcm_hw_params_alloca(&amp;m_HwParams);
  
          if ((err = snd_pcm_hw_params_malloc (&amp;m_HwParams)) &lt; 0) {
              fprintf (stderr, "Cannot allocate hardware parameter structure (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          if ((err = snd_pcm_hw_params_any (m_PlaybackHandle, m_HwParams)) &lt; 0) {
              fprintf (stderr, "Cannot initialize hardware parameter structure (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          if ((err = snd_pcm_hw_params_set_access (m_PlaybackHandle, m_HwParams, SND_PCM_ACCESS_RW_INTERLEAVED)) &lt; 0) {
              fprintf (stderr, "Cannot set access type (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          if ((err = snd_pcm_hw_params_set_format(m_PlaybackHandle, m_HwParams, SND_PCM_FORMAT_S16)) &lt; 0) { // Has to be 16 bit
              fprintf (stderr, "Cannot set sample format (%s)\n",
                       snd_strerror (err));
              exit (1);
  
          }
  
          uint sample_rate = 8000;
          if ((err = snd_pcm_hw_params_set_rate (m_PlaybackHandle, m_HwParams, sample_rate, 0)) &lt; 0) { // 8 KHz
              fprintf (stderr, "Cannot set sample rate (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          if ((err = snd_pcm_hw_params_set_channels (m_PlaybackHandle, m_HwParams, 1)) &lt; 0) { // 1 Channel Mono
              fprintf (stderr, "Cannot set channel count (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          /*
          Frames: samples x channels (i.e: stereo frames are composed of two samples, mono frames are composed of 1 sample,...)
          Period: Number of samples tranferred after which the device acknowledges the transfer to the apllication (usually via an interrupt).
          */
  
          /* Submit params to device */
          if ((err = snd_pcm_hw_params(m_PlaybackHandle, m_HwParams)) &lt; 0) {
              fprintf (stderr, "Cannot set parameters (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          /* Free the Struct */
          snd_pcm_hw_params_free(m_HwParams);
  
          // Flush handle prepare for record
          snd_pcm_drop(m_PlaybackHandle);
  
          if ((err = snd_pcm_prepare (m_PlaybackHandle)) &lt; 0) {
              fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  
          qDebug() &lt;&lt; "Done Setting up ALSA....";
  
          // Prepare the device
          if ((err = snd_pcm_prepare (m_PlaybackHandle)) &lt; 0) {
              fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                       snd_strerror (err));
              exit (1);
          }
  </code></pre>