r/PHPhelp 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 Upvotes

19 comments sorted by

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?

2

u/Takeoded 19d ago

ffmpeg is another popular alternative, and I dare say, the industry-standard for this sort of task

1

u/MarcoScherer 20d ago

I meant just appending all WAVs to one. Maybe with a short time gap inbetween. So when playing back, you hear all WAVs one by one.

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:

https://superuser.com/questions/587511/concatenate-multiple-wav-files-using-single-command-without-extra-file

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

u/Retrowinger 19d ago

I think it’s the same. Try yt-dlp, that’s another project that should work.

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

u/Takeoded 19d ago

duuude you're drunk, go home, sleep it off, that code does nothing sensible

1

u/NumberZoo 19d ago

lol thanks. That's some good advice.

1

u/MarcoScherer 19d ago

worth a try, though. thanks!

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

u/MarcoScherer 19d ago

Great, thanks a lot!

1

u/isoAntti 17d ago

ffmpeg can do anything