Go Down

Topic: Sample rate issue using WaveRP library (Read 32 times) previous topic - next topic

KashIO

I'm using a Waveshield on an Uno with the WaveRP library (https://code.google.com/archive/p/waverp/).

I can record files at any sample rate to the SD card with no problem using the WaveRecordPlay example, but when I play them back (using any of the WaveRP examples) the sample rate isn't correct - it seems fixed at 11kHz, so any files at 22kHz play back at half speed and corresponding low pitch, and even worse at 44.1k.

If I play the files back using the WaveHC library they play fine, so the recorded files themselves are ok - my guess is that it's something to do with the interrupt for the DAC, which is running on timer 1.

This is the section of the WaveRP.cpp file that sets up the interrupts:

Code: [Select]

// setup 16 bit timer1
static void setRate(uint16_t rate) {
  // no pwm
  TCCR1A = 0;
  // no clock div, CTC mode
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
  // set TOP for timer reset
  ICR1 = F_CPU / rate;
    // compare for DAC interrupt
  OCR1A = 1;
    // compare for SD interrupt
  OCR1B =  1;

}


When I change the value of ICR1 it doesn't appear to affect the rate at which the samples play back - surely this should determine the sample rate of playback?

Any thoughts would be most appreciated.

Kingsley






KashIO

It looks like the problem isn't with the interrupt, but with how long it's taking to read the data from the SD card - I'm getting a load of busyErrors on playback that I don't get on recording.

This is the interrupt code for the DAC:

Code: [Select]
// timer interrupt for DAC
ISR(TIMER1_COMPB_vect) {
  if (WaveRP::rpState != RP_STATE_PLAYING) {
    TIMSK1 &= ~_BV(OCIE1B);  // disable DAC timer interrupt
    return;
  }
  // pause has not been tested
  if (WaveRP::rpPause) return;
  if (rpIndex >= rpByteCount) {
    if (WaveRP::sdStatus == SD_STATUS_BUFFER_READY) {
      // swap buffers
      uint8_t *tmp = rpBuffer;
      rpBuffer = sdBuffer;
      sdBuffer = tmp;
      rpIndex = 0;
      rpByteCount = sdByteCount;
      WaveRP::sdStatus = SD_STATUS_BUFFER_BUSY;
      // cause interrupt to start SD read
      TIMSK1 |= _BV(OCIE1A);
    } else if (WaveRP::sdStatus == SD_STATUS_BUFFER_BUSY) {
      if (WaveRP::busyError != 0XFF) WaveRP::busyError++;
      return;
    } else {
      isrStop();
      return;
    }
  }
  uint16_t data;
  if (WaveRP::bitsPerSample == 8) {
    // 8-bit is unsigned
    data = rpBuffer[rpIndex] << 4;
    rpIndex++;
  } else {
    // 16-bit is signed - keep high 12 bits for DAC
    data = ((rpBuffer[rpIndex + 1] ^ 0X80) << 4) | (rpBuffer[rpIndex] >> 4);
    rpIndex += 2;
  }
#if DVOLUME
  if (WaveRP::volMult) {
    uint32_t tmp = WaveRP::volMult * (uint32_t)data;
    data = tmp >> 8;
    data += WaveRP::volOffset;
  }
#endif  // DVOLUME
  mcpDacSend(data);
}


and this is the interrupt code for the SD read/write:

Code: [Select]
// Interrupt for SD read/write
ISR(TIMER1_COMPA_vect) {
  // disable interrupt
  TIMSK1 &= ~_BV(OCIE1A);
  if (WaveRP::sdStatus != SD_STATUS_BUFFER_BUSY) return;
  sei();
//  Sd2Card *card = SdVolume::sdCard();
  if (WaveRP::rpState == RP_STATE_RECORDING) {
    // write 512 byte data block to SD
    if (!WaveRP::sdCard->writeData(sdBuffer)) {
      WaveRP::sdStatus = SD_STATUS_IO_ERROR;
      return;
    }
    WaveRP::sdCurPosition += 512;
    // check for end of preallocated file
    if (WaveRP::sdCurPosition >= WaveRP::sdEndPosition) {
      WaveRP::sdStatus = SD_STATUS_END_OF_DATA;
      // terminate SD multiple block write
      WaveRP::sdCard->writeStop();
      return;
    }
  } else if (WaveRP::rpState == RP_STATE_PLAYING) {
    sdByteCount = BUF_LENGTH;
    uint32_t dataRemaining = WaveRP::sdEndPosition - WaveRP::sdCurPosition;
    if (sdByteCount > dataRemaining) {
      sdByteCount = dataRemaining;
      if (sdByteCount == 0) {
        WaveRP::sdStatus = SD_STATUS_END_OF_DATA;
        return;
      }
    }
    uint32_t block = WaveRP::sdStartBlock + WaveRP::sdCurPosition/512;
    WaveRP::sdCurPosition += sdByteCount;
    if (!WaveRP::sdCard->readBlock(block, sdBuffer)) {
      WaveRP::sdStatus = SD_STATUS_IO_ERROR;
      return;
    }
  }
  cli();
  WaveRP::sdStatus = SD_STATUS_BUFFER_READY;
}


My guess is that the readBlock() function in this one is taking too long, so increasing the busyErrors count in the DAC interrupt?


Go Up