/** * Play a wave file. * * WaveHC::create() must be called before a file can be played. * * Check the member variable WaveHC::isplaying to monitor the status * of the player. */ void WaveHC::play(void) { // setup the interrupt as necessary int16_t read; playing = this; // fill the play buffer read = readWaveData(buffer1, PLAYBUFFLEN); if (read <= 0) return; playpos = buffer1; playend = buffer1 + read; // fill the second buffer read = readWaveData(buffer2, PLAYBUFFLEN); if (read < 0) return; sdbuff = buffer2; sdend = sdbuff + read; sdstatus = SD_READY; // its official! isplaying = 1; // Setup mode for DAC ports mcpDacInit(); // Set up timer one // Normal operation - no pwm not connected to pins TCCR1A = 0; // no prescaling, CTC mode TCCR1B = _BV(WGM12) | _BV(CS10); // Sample rate - play stereo interleaved OCR1A = F_CPU / (dwSamplesPerSec*Channels); // SD fill interrupt happens at TCNT1 == 1 OCR1B = 1; // Enable timer interrupt for DAC ISR TIMSK1 |= _BV(OCIE1A); }
/** * Play a wave file. * * WaveHC::create() must be called before a file can be played. * * Check the member variable WaveHC::isplaying to monitor the status * of the player. */ void WaveHC::play(void) { // setup the interrupt as necessary int16_t read; playing = this; // fill the play buffer read = readWaveData(buffer1, PLAYBUFFLEN); if (read <= 0) return; playpos = buffer1; playend = buffer1 + read; // fill the second buffer read = readWaveData(buffer2, PLAYBUFFLEN); if (read < 0) return; sdbuff = buffer2; sdend = sdbuff + read; sdstatus = SD_READY; // its official! isplaying = 1; // DAM: replacing DAC w/ PWM output // // Setup mode for DAC ports // mcpDacInit(); // DDRD |= (1 << 3); // Set up Timer 2 to do pulse width modulation on the speaker // pin. // Use internal clock (datasheet p.160) ASSR &= ~(_BV(EXCLK) | _BV(AS2)); // Set fast PWM mode (p.157) TCCR2A |= _BV(WGM21) | _BV(WGM20); TCCR2B &= ~_BV(WGM22); // Do non-inverting PWM on pin OC2B (p.155) // On the Arduino this is pin 3. TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0); TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0)); // No prescaler (p.158) TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // DAM: end. // Set up timer one // Normal operation - no pwm not connected to pins TCCR1A = 0; // no prescaling, CTC mode TCCR1B = _BV(WGM12) | _BV(CS10); // Sample rate - play stereo interleaved OCR1A = F_CPU / (dwSamplesPerSec*Channels); // SD fill interrupt happens at TCNT1 == 1 OCR1B = 1; // Enable timer interrupt for DAC ISR TIMSK1 |= _BV(OCIE1A); }
/** * Read a wave file's metadata and initialize member variables. * * \param[in] f A open FatReader instance for the wave file. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. Reasons * for failure include I/O error, an invalid wave file or a wave * file with features that WaveHC does not support. */ uint8_t WaveHC::create(FatReader &f) { // 18 byte buffer // can use this since Arduino and RIFF are Little Endian union { struct { char id[4]; uint32_t size; char data[4]; } riff; // riff chunk struct { uint16_t compress; uint16_t channels; uint32_t sampleRate; uint32_t bytesPerSecond; uint16_t blockAlign; uint16_t bitsPerSample; uint16_t extraBytes; } fmt; // fmt data } buf; #if OPTIMIZE_CONTIGUOUS // set optimized read for contiguous files f.optimizeContiguous(); #endif // OPTIMIZE_CONTIGUOUS // must start with WAVE header if (f.read(&buf, 12) != 12 || strncmp(buf.riff.id, "RIFF", 4) || strncmp(buf.riff.data, "WAVE", 4)) { return false; } // next chunk must be fmt if (f.read(&buf, 8) != 8 || strncmp(buf.riff.id, "fmt ", 4)) { return false; } // fmt chunk size must be 16 or 18 uint16_t size = buf.riff.size; if (size == 16 || size == 18) { if (f.read(&buf, size) != (int16_t)size) { return false; } } else { // compressed data - force error buf.fmt.compress = 0; } if (buf.fmt.compress != 1 || (size == 18 && buf.fmt.extraBytes != 0)) { putstring_nl("Compression not supported"); return false; } Channels = buf.fmt.channels; if (Channels > 2) { putstring_nl("Not mono/stereo!"); return false; } else if (Channels > 1) { putstring_nl(" Warning stereo file!"); } BitsPerSample = buf.fmt.bitsPerSample; if (BitsPerSample > 16) { putstring_nl("More than 16 bits per sample!"); return false; } dwSamplesPerSec = buf.fmt.sampleRate; uint32_t clockRate = dwSamplesPerSec*Channels; uint32_t byteRate = clockRate*BitsPerSample/8; #if RATE_ERROR_LEVEL > 0 if (clockRate > MAX_CLOCK_RATE || byteRate > MAX_BYTE_RATE) { putstring_nl("Sample rate too high!"); if (RATE_ERROR_LEVEL > 1) { return false; } } else if (byteRate > 44100 && !f.isContiguous()) { putstring_nl("High rate fragmented file!"); if (RATE_ERROR_LEVEL > 1) { return false; } } #endif // RATE_ERROR_LEVEL > 0 fd = &f; errors = 0; isplaying = 0; remainingBytesInChunk = 0; #if DVOLUME volume = 0; #endif //DVOLUME // position to data return readWaveData(0, 0) < 0 ? false: true; }
int main( int argc, char *argv[] ) { if ( argc != 2 ) /* argc should be 2 for correct execution */ { /* We print argv[0] assuming it is the program name */ printf( "usage: %s filename\n", argv[0] ); return 0; } else { // Application simply decodes wav files printf("This is C application written by Nerijus\n"); //Local variables char fileName[] = "sample.wav"; strcpy ( fileName, argv[1] ); struct wav_file *waveData = malloc(sizeof *waveData); //----- PaStreamParameters outputParameters; PaStream *stream; PaError err; //paTestData data; int i; readWaveData(fileName, waveData); printWaveData(waveData); printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", waveData->sampleRate, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ /* for( i=0; i<TABLE_SIZE; i++ ) { data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); } data.left_phase = data.right_phase = 0; */ err = Pa_Initialize(); if( err != paNoError ) goto error; outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ if (outputParameters.device == paNoDevice) { fprintf(stderr,"Error: No default output device.\n"); goto error; } //outputParameters.channelCount = 2; /* stereo output */ outputParameters.channelCount = 2; /* stereo output */ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; /* err = Pa_OpenStream( &stream, NULL, // no input &outputParameters, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, // we won't output out of range samples so don't bother clipping them patestCallback, &data ); */ err = Pa_OpenStream( &stream, NULL, // no input &outputParameters, 8000, FRAMES_PER_BUFFER, paClipOff, // we won't output out of range samples so don't bother clipping them patestCallback, waveData ); if( err != paNoError ) goto error; // sprintf( data.message, "No Message" ); err = Pa_SetStreamFinishedCallback( stream, &StreamFinished ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Play for %d seconds.\n", NUM_SECONDS ); Pa_Sleep( NUM_SECONDS * 1000 ); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); free(waveData->data); free(waveData); return err; error: Pa_Terminate(); free(waveData->data); free(waveData); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } }