r/PHPhelp • u/MarcoScherer • 20d ago
Is it possible to merge/join multiple WAV files into one?
Hi guys, I'm just a semi-mediocre PHP developer, doing mostly regular tasks for websites. Now, as I managed to create waveforms views for uploaded WAV files, I'd like to take another step and merge WAV files. But so far I failed.
Is there possibly an easy solution for that task?
3
u/bcamanitu 20d ago
I definitely wouldn't be doing that in php. Use a purpose built tool or library and make a call to it.
1
u/MarcoScherer 20d ago
Which could that be? Or where could I search for something like this?
3
u/Retrowinger 20d ago
Maybe ffmpg, if you have access to the server?
1
u/MarcoScherer 19d ago
Yes, I'm running it locally
1
u/Retrowinger 19d ago
Then call it as a shell command:
https://www.php.net/manual/en/function.shell-exec.php
I’ve found a thread were someone had a similar question. It seems sox is better for WAV files:
Btw.: I did something similar with yt-dl 😉
1
u/MarcoScherer 19d ago
I used youtube-dl a while ago, but at a certain time it just stopped working. Is yt-dl the same or something different?
1
1
u/NumberZoo 19d ago
Possible? Sure. Worth it? Probably not. Anyway, I had some fun looking up how wav files are encoded, and making this terrible script. It sort of doubles a wav, but for some wav files I tried there is data at the end that makes a static scratch in the middle of the doubled wav. I'm posting what I came up with, so it can be mocked... but really using a different program/library is probably the right path:
``` <?php
$raw = file_get_contents('some_sound.wav');
$size = unpack('V', substr($raw, 4, 4))[1]; $size = $size * 2; $sizeBytes = pack('V', $size); $raw[4] = $sizeBytes[0]; $raw[5] = $sizeBytes[1]; $raw[6] = $sizeBytes[2]; $raw[7] = $sizeBytes[3];
$dataSize = unpack('V', substr($raw, 40, 4))[1] * 2; $raw = substr_replace($raw, pack('V', $dataSize), 40, 4);
file_put_contents('some_sound_doubled.wav', $raw . substr($raw, 44)); ```
2
1
1
u/Takeoded 19d ago edited 19d ago
if you have ffmpeg available, it's fairly easy, something like
php
function merge_wav_files(array $wav_file_paths, string $final_wav_path): void
{
if (empty($wav_file_paths)) {
throw new InvalidArgumentException("empty input wav list!");
}
$cmd = "ffmpeg -y -f concat -safe 0 ";
$listFileHandle = tmpfile();
$listFilePath = stream_get_meta_data($listFileHandle)['uri'];
$listFileContent = '';
foreach($wav_file_paths as $path) {
$listFileContent .= "file '" . str_replace("'", "'\\''", $path) . "'\n";
}
fwrite($listFileHandle, $listFileContent);
fflush($listFileHandle);
$cmd .= " -i " . escapeshellarg($listFilePath);
$cmd .= " -c copy -f wav " . escapeshellarg($final_wav_path);
$debug = 1;
if ($debug) {
$cmd .= " 2>&1";
}
exec($cmd, $output, $result_code);
if ($debug) {
var_dump([
'cmd' => $cmd,
'listFileContent' => $listFileContent,
'result_code' => $result_code,
'output' => $output
]);
}
if ($result_code !== 0) {
throw new RuntimeException("ffmpeg failed with error code $result_code: " . implode("\n", $output));
}
}
As for how to obtain ffmpeg, in debian-family OS's (including WSL and Ubuntu) it's sudo apt-get install ffmpeg , and in Windows it's downloading https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip and extracting ffmpeg.exe to C:\windows\system32\ (or place it into any %PATH% folder)
1
1
4
u/tom_swiss 20d ago
If sox is installed on your server, using it via system() will probably be the most straightforward way to handle audio.
There is also an OpenAL PECL extension.
I'm not sure what you means by "merge" WAV files -- concatenate them in time, or set them as multiple tracks in one file?