/** * Append a wav file to the current wav. <br /> * The wav files must have the same sample rate, number of bits per sample, and number of channels. * * @param Yop_Poll_WavFile $wav (Required) The wav file to append. * * @throws Yop_Poll_WavFileException */ public function appendWav(Yop_Poll_WavFile $wav) { // basic checks if ($wav->getSampleRate() != $this->getSampleRate()) { throw new Yop_Poll_WavFileException("Sample rate for wav files do not match."); } else { if ($wav->getBitsPerSample() != $this->getBitsPerSample()) { throw new Yop_Poll_WavFileException("Bits per sample for wav files do not match."); } else { if ($wav->getNumChannels() != $this->getNumChannels()) { throw new Yop_Poll_WavFileException("Number of channels for wav files do not match."); } } } $this->_samples .= $wav->_samples; $this->setDataSize(); // implicit setSize(), setActualSize(), setNumBlocks() return $this; }
/** * Generate a wav file given the $letters in the code * @todo Add ability to merge 2 sound files together to have random background sounds * @param array $letters * @return string The binary contents of the wav file */ protected function generateWAV($letters) { $wavCaptcha = new Yop_Poll_WavFile(); $first = true; // reading first wav file foreach ($letters as $letter) { $letter = strtoupper($letter); try { $l = new Yop_Poll_WavFile($this->audio_path . '/' . $letter . '.wav'); if ($first) { // set sample rate, bits/sample, and # of channels for file based on first letter $wavCaptcha->setSampleRate($l->getSampleRate())->setBitsPerSample($l->getBitsPerSample())->setNumChannels($l->getNumChannels()); $first = false; } // append letter to the captcha audio $wavCaptcha->appendWav($l); // random length of silence between $audio_gap_min and $audio_gap_max if ($this->audio_gap_max > 0 && $this->audio_gap_max > $this->audio_gap_min) { $wavCaptcha->insertSilence(mt_rand($this->audio_gap_min, $this->audio_gap_max) / 1000.0); } } catch (Exception $ex) { // failed to open file, or the wav file is broken or not supported // 2 wav files were not compatible, different # channels, bits/sample, or sample rate throw $ex; } } /********* Set up audio filters *****************************/ $filters = array(); if ($this->audio_use_noise == true) { // use background audio - find random file $noiseFile = $this->getRandomNoiseFile(); if ($noiseFile !== false && is_readable($noiseFile)) { try { $wavNoise = new Yop_Poll_WavFile($noiseFile, false); } catch (Exception $ex) { throw $ex; } // start at a random offset from the beginning of the Yop_Poll_WavFile // in order to add more randomness $randOffset = 0; if ($wavNoise->getNumBlocks() > 2 * $wavCaptcha->getNumBlocks()) { $randBlock = rand(0, $wavNoise->getNumBlocks() - $wavCaptcha->getNumBlocks()); $wavNoise->readWavData($randBlock * $wavNoise->getBlockAlign(), $wavCaptcha->getNumBlocks() * $wavNoise->getBlockAlign()); } else { $wavNoise->readWavData(); $randOffset = rand(0, $wavNoise->getNumBlocks() - 1); } $mixOpts = array('wav' => $wavNoise, 'loop' => true, 'blockOffset' => $randOffset); $filters[Yop_Poll_WavFile::FILTER_MIX] = $mixOpts; $filters[Yop_Poll_WavFile::FILTER_NORMALIZE] = $this->audio_mix_normalization; } } if ($this->degrade_audio == true) { // add random noise. // any noise level below 95% is intensely distorted and not pleasant to the ear $filters[Yop_Poll_WavFile::FILTER_DEGRADE] = rand(95, 98) / 100.0; } if (!empty($filters)) { $wavCaptcha->filter($filters); // apply filters to captcha audio } return $wavCaptcha->__toString(); }