Generating MP3 waveforms with PHP

UPDATE: After some great comments, I have optimized the performance of this script and made some brief commentary available here. I have also updated any source code links below to the new github project page.

I don’t quite know what gave me the desire to ever generate audio (specifically MP3) waveforms with PHP — it’s not something I’ll likely ever use — but after doing some research and coming up a bit short I decided to make it happen.

Waveform generated using Dancing With Paris' "(Boardwalk)" MP3.

A few days of Googling, I did come up with a couple solutions but none seemed to really produce the results I wanted. All I was looking to generate was a simple waveform like that in Cubase or other recording software. I don’t need axis labels or left/right audio splits, just a simple mono waveform from an MP3. I also didn’t want to go through hundreds of audio files and convert them into WAV files just to do this — if I was going to do this as an experiment, I wanted it on the fly. I did come across some interesting links though:

The Sound eXchange (SoX) audio tool kit has a lot of great features that might come in handy later on, including audio effects, but support for MP3 wasn’t built-in and seemed a bit too much work to bother compiling just for a side experiment. SoX can generate spectrograms, but this wasn’t particularly what I was looking for.

I did find this classAudioFile.php, which does support generating waveforms from WAV files, but this seemed a bit more hefty than I really needed — and not as accomplishing as doing it myself. That being said, and though I never bothered testing it out, it does seem (based on the code) to create a simple waveform image that I was aiming to create.

Ultimately, I wanted something flexible: upload MP3s files without pre-converting them, adjust size of the image easily, and change foreground and background colours. The key that makes my script different, and most flexible, is converting the files to WAV on the fly. Though this is time consuming, it’s ultimately a lot easier than batch processing them on my computer first.

Click here to see the source code for the script.

The key to making this convenient has been using the LAME MP3 encoder/decoder through the command line (on Windows for my script, I haven’t yet tested with any flavour of Linux). I simply downloaded a windows build of LAME, threw the executable into my script directory and ran the following command:

lame original_file.mp3 -f -m m -b 16 --resample 8 resampled.mp3 && lame --decode resampled.mp3 final_file_for_processing.wav

Because you don’t really need a high quality audio file for generating a waveform, this set of commands will resample the original MP3 to a 16 bit, 8 KHz, mono MP3 file and then turn that into a WAV file for processing the image from. Processing does take some time, but it’s significantly faster than processing a huge 40+ MB WAV file from the start. Also, no amount of research showed a way to directly downsample an MP3 straight to a WAV file, hence the intermediary step.

After that, I used an algorithm I found on the DevShed forums for processing 16 bit WAV files, and used the data it generates to create the waveform (which, ultimately, is pretty simple).

If this is something you have a use for, feel free to use it as you wish and give credit where it’s due (see the source comments for where I pulled some code snippets from to make this work). You may want to fix it up a bit for better error checking and so forth though.

A note of warning: it’s not fast. Far from it. A couple basic tests showed anywhere between 10-30+ seconds to generate the waveforms for an average sized MP3 (decent quality, 2-4 minutes in length). If you will be generating and re-generating waveforms multiple times for the same audio file, you may want to cache the WAV data in a database for future use, as using that data to create the image itself is comparatively quite quick.

I may use this, along with the SoX library, later on to create — simply for fun and discovery — an online audio mixer/editor similar to Cubase, which I’ve been working with quite a lot lately. This would be a great way to create a new web-based interface with a lot of widgets and controls not commonly used, as well as using SoX to add audio effects, mix, combine files, in a multi-layered audio interface. I’ll see if I ever get around to this however.

Environment tested in, your results may vary:

  • Windows Server 2003
  • PHP 5.2.10
  • LAME 3.98.4


I’ve been so kind as to release this code under the Apache License v2.0, which means you’re more than welcome to use, distribute, and modify this code as long as you follow the terms of the license (which includes keeping the license with the modified source code).

This is by far my most popular blog entry — and thus I can assume the most desired piece of code that I’ve so far provided. If this code has been useful to you, and if you can find it in your heart, please donate a dollar or two. If you can buy me a coffee I’d be eternally grateful. Below is a donate button for my PayPal account.

98 thoughts on “Generating MP3 waveforms with PHP

  1. regeda

    It’s cool! You are great! Thanks for code

  2. Romain

    Thank you very much ! I was looking for this code long time, it’s really interesting.

  3. Hi Andrew, this is really good. I was looking at trying to do this a while ago but never found the time to start; it looks like you’ve made fantastic progress! Thanks so much for sharing the code with everyone 🙂

    The next step (although I don’t even think it’s feasable) would be to get rid of the dependency for LAME…

  4. Thank you Andrew, this is exactly what I had been looking for. I was starting to think I would have to hire someone to code something similar.

    Thanks again,

  5. Pandronic

    I don’t know why you said it was slow. For a 3:39 long MP3 I got:

    LAME conversion: 2.92 sec
    Processing: 0.35 sec
    Image generation: 0.60 sec

    Total: 3.87 sec

    • Andrew

      Haha, great! Well I should have added a note that I was using an older Core Duo 1.83 GHz laptop and that ones mileage may vary.

      I’m very happy that it’s working for you though. If you have any improvements please don’t hesitate to let me know.

      • Pandronic

        2.2Ghz Dual Core here. I’m making some improvements in the way the image is plotted. I’ll get back with the modifications. Great piece of code BTW.

    • Ben

      Very nice – just need to implement it into my component now.

      Just out of interest – the file mentioned – what bitrate was it and or filesize?

      Would be handy to know ( ie do i need another server or not…)

      • Andrew

        The original MP3 file I reference in the article above is the following:

        File Size: 19.56 MB
        Length: 1 minute, 56 seconds
        Sample Rate: 44.1 KHz
        Sample Size: 16 bit
        Bit Rate: 320 kbps

        I just ran the script again on my laptop (Windows 7, Core Duo T2400 1.83 GHz, 3 GB RAM) and it took 4.76 seconds to process this file.

        Hope that helps!

  6. I got it working on my website too, thanks!
    works on linux with lame, PHP Version 5.2.13 too.

  7. excellent! thanks so much for this. worked perfectly on ubuntu.

  8. j

    Excellent, it’s really usefull. But i’ve a question… some times I can’t get a amplified waveform enough. How can i modify the waveform amplitude ?

    • Andrew

      I didn’t experiment with a great deal of different MP3 files when I first wrote this script, but you might want to do that yourself to compare what sorts of results you are getting. Take a look into this particular line:

      imageline($img, $d / DETAIL, 0 + ($height – $v), $d / DETAIL, $height – ($height – $v), imagecolorallocate($img, $r, $g, $b));

      Bolded arguments indicate the height/amplitude that will be drawn to the waveform at a particular point.

  9. Hi Andrew,

    I would like to publish a Drupal module that implement your script with adaptation to Drupal.
    I will give you the proper credit, I just want to get your permission and also I need to publish it under GPL license.


    • Andrew

      Hi Brice,

      Sorry for the delay in my response.

      I certainly don’t have a problem with releasing this code as a Drupal module under a different license. All I ask is that you please link to this original blog entry, and if feeling particularly kind you can always donate a few dollars to my PayPal account, linked at the bottom of the blog entry.

      I’m not too familiar with Drupal at all to be honest, but if there’s any insight I can offer that might help you make this into a good module that will help others please don’t hesitate to let me know.


  10. Thanks Andrew for the code…it working fine ,but it is utilising more memory usage in log ,how to resolve this

    • Andrew

      Not a problem at all, I’m glad this code is of interest to you.

      I would try experimenting a bit more with different MP3 files of varying lengths of bitrate qualities to see if you can find a sweet spot for your quality of waveform and memory usage/processing time. Also, try playing around a bit with the DETAIL constant I defined in the script to see what values might be best.

      It’s hard to give much other advice without any more detail. Consider installing Xdebug and WinCacheGrind so you can analyze the script in more detail on your system to determine what portions of the code are taking the longest/eating the most memory. These are definitely essential tools for optimizing code.

      • Thanks Andrew for ur reply,I have executed the code on different wav files…most of them are working fine,but for some files fopen() is not working,i think it might be wav file problem,for that files it is using more memory while executing

      • Thanq Andrew for the code,with little changes now i can run .MP3,.Wav and Mp3 to wav converted files.

  11. sortedmush

    Hi. I’ve been searching for days with no luck for a php script to output a wav file, and then call LAME to convert to mp3.

    I’m trying to output dynamically generated audio. Any advice?


  12. Gústi

    Awesome stuff.

    Any tips on adding opacity to color selection? I’d just love to be able to make a coloured waveform on a transparent background or the other way around.

  13. Adam

    love it!

    one thing though: your default colors inside the script are both red “#FF0000”

    so where it says:
    $foreground = isset($_POST[“foreground”]) ? $_POST[“foreground”] : “#FF0000”;
    $background = isset($_POST[“background”]) ? $_POST[“background”] : “#FF0000”;

    i think you wanted it to say:
    $foreground = isset($_POST[“foreground”]) ? $_POST[“foreground”] : “#FF0000”;
    $background = isset($_POST[“background”]) ? $_POST[“background”] : “#FFFFFF”;

    (notice the background color default is FFFFFF)

    • Andrew

      Hi Adam, I fixed the little error. Thank you for pointing this out!

  14. Hi ! Congratulations for your post ! Its awsome ! Learned a lot with !
    Thanks !

    Btw.. Im trying to test this bit its not working. Actually nothing happens ! What i am doing wrong ? Maybe im not instaLling properly the laMe codec. Could u haelp me with ? How can i install the lame and run the code in my apache server ? I use wampp server btw.

    Thanks in advnce ! And congrats again !

    • Andrew

      It’s hard for me to say why it wouldn’t be working. I can suggest the follow things:

      – Make sure PHP error reporting is turned on
      – Check your php.ini config to see what your safe_mode_exec_dir setting is
      – Print out the LAME exec() command string, copy and paste it into terminal/command prompt from that directory and see if you are getting any errors
      – Perform some basic debugging: Use xdebug and var_dump variables throughout to see what might be happening

      Hope that helps.

  15. Lee

    now, the next step would be to make the waveform clickable, to be able to play back the audio and skip to different sections of the song… thanks for sharing, helped me create something id been meaning to do for a whilem after trying lots of other tedius solutions, this one file solutions rocks… now, if i can only save the image as a proper png and load it into a page… then acurately measure where the mouse is over the image, and relate it somehow to the playback…. eeek, overload.

    • Andrew


      This actually really wouldn’t be too difficult. You might want to look into something like SoundManager 2 as a great Javascript-controlled audio player.

      You could skip to various parts of the song by determining where (on the horizontal axis) in the image the user clicked, and skip ahead in the audio using SoundManager 2. Here’s a quick example (off the top of my head, haven’t tested this, more as pseudocode than anything), assuming you’re using jQuery:

      $(“#some_waveform”).click(function(e) {
      // determine how far across horizontally the waveform was clicked
      var percent_pos = (e.pageX – $(this).offset().left) / $(this).width();
      soundManager.setPosition(‘mySound’, mySound.duration * percent_pos);

      Hope that helps. Definitely look into SoundManager 2 as linked above, look through the documentation. It sounds to me like it’s very close to what you might be looking for.

      • Scott Schiller

        I took an approach much like this for the “Wheels Of Steel” turntable prototype ( ), which uses both SM2 and the script provided here for generating the waveform. Thanks for that, it’s worked quite well.

        Andrew is correct; provided you can get the offsets of the waveform relative to the mouse, it’s pretty easy to seek within the sound; it’s safest if the whole sound has loaded, otherwise if seeking before load has completed you can use sound.durationEstimate.

        The Wheels Of Steel allows seeking via the waveform, shows progress of the track and cue points along the “timeline” of the waveform as well; the code’s over on Github if you want to poke around.

        • Andrew

          Hey Scott,

          Thanks for dropping by and leaving a comment. I’m very happy to see that you’ve released your project on github for all to see. I’ve taken a look at the live project and it’s fantastic — definitely very motivating and inspiring. I will certainly be using your source as a reference point for if/when I finally get around to making a web-based DAW, or my best attempt at replicating one, on my free time.

  16. Dave T

    Hi, I’m trying to get this running on MAC OS 10.5.8 via localhost using MAMP with PHP 5.3.5.

    After hours of reading stuff on the net I just can’t work out how to install LAME on my system (it’s seems to be a breeze for Windows users but nobody has taken the time to explain the install method for Mac’s sadly) and obviously without it the program hangs when I try to run it.

    Is there any way of bypassing the mp3-wav conversion ib the script and having it just process the raw wav files instead? As I said, I’m doing this locally so file size isn’t an issue.

    Many thanks in advance.

  17. Dave T

    Ok I found a compiled version of Lame for Mac OSX and it’s working now from the command line.

    But the script is having problems creating the tmp file.

    This is from my apache error log :

    Could not find “{}_o.mp3”

    The original file is being uploaded to /tmp but it’s not being created.

    I’m assuming that the temp_o.mp3 is supposed to be created in the current dir that waveform.php is running in right? my path is htdocs/wform/waveform.php so I’ve CHMODed the wform folder to 755 but it’s not happening.

    Am I doing something wrong?

    Many thanks in advance.

    • Dave T


      Found the problem (kinda)

      A temp file was being created but then being deleted right away the @unlink functions.

      So I disabled them and now I can see the file being generated (here is one for example – ‘c3ba3cd8e0_o.mp3’)

      But i’m still getting the same apache error as before : Could not find “{}_o.mp3”.

      It seems that the name string isn’t being written properly. Any ideas?

      • Dave T

        Wow.. Just tried to open my php_error.log to see what was going wrong and it crashed the console.. The log file was over 8GB!

        Deleted it and created a blank one, ran the script once and it started filling up the error log right away. I stopped it after about 9 seconds and it had already filled the error log with 15MB of data!

        This is the gist of it…

        [29-Aug-2011 20:20:36] PHP Warning: fopen(d619b779be.wav) [function.fopen]: failed to open stream: No such file or directory in /Applications/MAMP/htdocs/waveform.php on line 256
        [29-Aug-2011 20:20:36] PHP Warning: fread(): supplied argument is not a valid stream resource in /Applications/MAMP/htdocs/waveform.php on line 258
        [29-Aug-2011 20:20:36] PHP Warning: fread(): supplied argument is not a valid stream resource in /Applications/MAMP/htdocs/waveform.php on line 310
        [29-Aug-2011 20:20:36] PHP Warning: feof(): supplied argument is not a valid stream resource in /Applications/MAMP/htdocs/waveform.php on line 286

        and then just repeats the last two errors in a loop until I shut down the server..

        Does that help with diagnosis at all?

        P.S I moved waveform.php back to the root just to avoid confusion with my previous post.

        • Andrew

          Please post a copy of the modified script you are using to something like and pass along the URL so that I might be able to take a look.

  18. Dave T

    Hi Andrew,

    Thanks for your reply.

    As far as I’m aware it hasn’t been modified at all apart from where I’ve told the exec() command to point to my install of Lame.

    Here you go :



    • Andrew

      So a couple of things after my first browse of your source:

      On line 242 (the exec() function line), make sure you are using double quotes to encapsulate the string instead of single quotes (” instead of ‘). Variables in single quoted strings will not be expanded, so use of {$somevariable} needs to occur within double quoted strings. Please see the PHP documentation at This is likely the cau

      If that fails, try chmod’ing the directory to 777 instead of 755 so that all owner/group/others have write permissions.

      I can’t see much else wrong right now, but I just took a quick browse through. Try putting an exit; statement before the two unlink function calls (lines 245 and 246) and check the directory to ensure that the uploaded file, the reduced MP3 file and the final WAV file are there.

      Hope that helps!

  19. Dave T

    Hi Andrew,

    Thanks so much, we’ve had some progress here 😉

    I followed your instructions about the double quotes and the exit; and I’m now getting the original mp3, the resampled mp3 & the wav just fine but then the script just pops up a blank screen. Not getting any image output.

    Do I need to specify a location or change a setting somewhere?

    • Dave T

      In case it helps here is my Apache error log. There doesn’t seem to be any PHP errors being generated at all so that’s a good thing 😉

      • Dave T


        Scrap that last comment, I removed the exit; and it’s working like a charm 😉

        Thanks so much for your help and your excellent code!

        Do you know if anybody managed to work out what needs to be changed to output the background as transparent? That would be awesome!

        • Andrew

          Excellent, glad you got it working!

          No one has provided anything in terms of transparent backgrounds, but since it’s already outputting a PNG, adding transparency shouldn’t be difficult. I’ll get to this when I’m not as busy with work in a couple of days, but in the mean time I encourage you to give it a try yourself. 🙂

          I’ll keep you posted when I have a few minutes and throw together a quick solution.


          • Dave T

            Ok that would be great, in the meantime i’ll also have a look and see if I can find a way to do it.

            I do have one little problem with the image that’s currently being generated though.

            I just tried to download it and it’s not a valid png image! I can’t import it into anything like photoshop or even drop it in a browser. No matter what I rename the file any app I try to open it with seems to think that it’s a php file and not a png. Any ideas why that is?

            I can see the image but I can’t use it, it’s like it’s dangling a carrot in front of me but I just can’t take a bite 😉

  20. Dave T

    I’ve asked a lot so now it’s time to share just in case anybody else wants to do what I required..

    It’s very basic for those that know php, but for people like me still finding their feet I hope it helps.

    I didn’t want to use random file names and also wanted to store the png file & original mp3 on my server for each upload, so here goes..

    // set up filename from uploaded file

    find :

    $tmpname = substr(md5(time()), 0, 10);

    replace with :

    $tmpname = $_FILES[‘mp3’][‘name’];

    find :

    copy($_FILES[“mp3”][“tmp_name”], “{$tmpname}_o.mp3″);

    replace with :

    copy($_FILES[“mp3”][“tmp_name”], “{$tmpname}”);

    // Filename fixes in the lame exec. I also chose to drop the 8bit downsampling as the results are way more accurate in 16bit

    find :

    exec(‘lame {$tmpname}_o.mp3 -f -m m -b 16 –resample 8 {$tmpname}.mp3 && lame –decode {$tmpname}.mp3 {$tmpname}.wav’);

    replace with :

    exec(“lame {$tmpname} -f -m m -b 16 {$tmpname}_c.mp3 && lame –decode {$tmpname}_c.mp3 {$tmpname}.wav”);

    // DON’T erase the original uploaded mp3 but make sure we lose the new converted one.

    find :


    replace with :


    // Set up png file name as ‘originalfilename.png’ (stripping the mp3 extension) and store on server.

    find :


    replace with :

    $file = “{$tmpname}”;
    $name = basename($file, ‘.mp3′);
    imagepng($rimg, “{$name}.png”);

    // and do the same for the non-resized image output

    find :


    replace with :

    $file = “{$tmpname}”;
    $name = basename($file, ‘.mp3′);
    imagepng($img, “{$name}.png”);

    That’s it.. Just be aware that if you upload something with the same file name it will overwrite the one that’s already there without warning. This could be easily fixed but I don’t need that feature for my purposes.

    I’m sure there is probably a much more streamlined way to do all of this but it works

  21. Dude, you rock! Thank you for the detail setting! 😀

  22. Great stuff, thanks a bunch!

    I’ve rewritten your script mainly to improve performance and reduce memory usage on large wave files (I use it for 2 hour DJ sets). I’ve also made the detail tweakable via a zoom factor and the option of reading several values for one data point (line in the waveform) to reduce the chance of reading an value not representable for that block of audio.

    The code (and some more explaination) can be found at my blog:

  23. Jonathan Smith

    Thank you from the bottom of my heart. You’re a fantastic coder. I’ll make sure I give this site credit and I’m sure my visitors will love the new feature 😉

  24. For a more solid waveform you can use “imagesetthickness”. Just insert the following code somewhere near line 352 (just before you loop through the frames/bytes of wav data) and also make sure you have DETAIL set to 1 for best results.

    $size = sizeof($data);

    if($size < $width)
    $thickness = 1;
    $thickness = $size / ($width * 2); // thickness is half a pixel

    imagesetthickness ($img,$thickness);

  25. Tim

    Fantastic work, thx!!!
    We have implemented this into our site and it works great except that occasionally the waveform generation gets corrupted, as in this example:
    Has this happened to anyone else?

  26. Aaron

    Hi Andrew, thanks a lot for this great script. Works a treat!

    I am hoping to use this for a custom Drupal module. Of course I would like to properly credit you for the hard work that has gone into this so if you could let me know how you would like acknowledgement that would be great. (especially with regard to licensing)

    Thanks again for this great script.

    • Andrew

      Hi Aaron,

      Thanks for the kind words, greatly appreciated.

      I’m trying not to be too picky on licensing, but if you could keep the original Apache license text found on my source code with your modified script that would be great — this would hopefully ensure that the code can be continually passed around, borrowed and modified as truly open source. As far as acknowledgement, if you could just make a quick mention of my name and my site ( alongside the source then I would be more than grateful.

      Thanks again and I’m glad it’s been helpful. I’m not a Drupal guy in the slightest, but if there’s anything I might be able to help with please don’t hesitate to let me know.


  27. Tom


    You could easily improve the performance of your script ten fold by putting in a modulo to the file read loop and modifying your for loop to not increment the data by the detail. Since you are reading the data only to discard it in the for loop it’s a waste of processing and memory (to store the data only to throw it away later).

    $loop = 0;
    while( !feof( $handle)) {
    if( $loop % DETAIL == 0 ) {
    // do your byte extraction
    fread( $handle, $omjer);

    Then modify your for loop to be:
    for( $d = 0; $d < sizeof($data); $d++ ) {
    // Do your draw event

    This prevents you from having to save data in the $data array that you aren't going to use to draw later. The only real side effect of this change is that it does make the DETAIL a little bit sensitive to changes. So values larger than 30 will result in "blocky" results in the waveform. However the trade off in performance is massive. Unless you select 1 as your DETAIL level, you effectively cut more and more data out of the data array, reducing memory utilization, as well as time to complete the computation.

    • Andrew

      Hi Tom,

      Very excellent point! I might even take that very simple, very smart idea one step further: see if the size (i.e. number of data points) of the waveform can be accurately predetermined without reading the entire file into memory. If possible, then the waveform points could be drawn straight to the image handler without even having to store them in any $data variable, reducing the need for a second loop.

      Worst case: determine a best guess of the number of $data points simply by grabbing a filesize() result, drawing the canvas and all of the waveform points… then, knowing the true number of data points (given DETAIL), crop the canvas down to the correct size? Does that make sense or is it just late in my timezone and I’m getting tired?

      In some ways I don’t mind grabbing all of $data, only to throw away some of it at the time of rendering the image. Depending on the application, all of those data points could be stored so that the waveform could be redrawn again at any time and at any “DETAIL” level. If that’s the case, that would be faster in the long run than re-processing the MP3 file with lame and reading from the resulting WAV character by character. I imagine even a simple unserialize(file_get_contents(“stored_data_points.txt”)) would be faster than reprocessing all over again.

      Hopefully any of that makes sense and I’m not embarrassed by this commentary in the morning when I reread it. Let me know your thoughts.

      There’s definitely some interest here from a number of people so I really should get it up on github so those with great suggestions like this can directly contribute.


      • Andrew

        For what it’s worth, I figured out how to properly estimate the total estimated number of data points that are going to be extracted. The math is:

        $total_data_size = (($size_of_wav_file – $header_bytes) / ($ratio + $byte)) – 1


        $size_of_wav_file is a simple filesize($filename)
        $header_bytes is the number of bytes read initially from the wav file (constant of 44)
        $ratio is the number of bytes skipped at the end of reading each data point in the while(!feof($handle)) loop
        $byte is determined from the $peek data (just after reading the wav headers)
        – 1 to account for an extra byte somewhere

        This has been giving me accurate results for a small subset of tests I ran.

        Given this, I should be able to modify the script to skip a $data array altogether and draw straight to the canvas while reading the file.

        I’ll play around with this and post an updated version when I have something working (along with a couple of memory usage (memory_get_peak_usage())/execution time benchmarks).

  28. Ruckus

    Hi all,

    I tried to modify the script for creating a transparent foreground. Unfortunately the wafeform is white and not transparent as it should be 🙁
    I used “imagecolortransparent” to replace the white with transparency.

    My demo with a transparent rectangle works fine:

    $img = imagecreatetruecolor(640, 100);
    $white = imagecolorallocate($img, 255, 255, 255);
    $black = imagecolorallocate($img, 0, 0, 0);

    // draw white rectangle
    imagefilledrectangle($img, 0, 0, 640, 100, $white);
    $subtrakt = imagecolortransparent($img, $black);
    imagefilledrectangle($img, 20, 20, 620, 80, $subtrakt);

    // save the image
    imagepng($img, ‘demo.png’);

    But with the waveform-script there is only the white waveform:

    // fill background of image
    list($r, $g, $b) = html2rgb($background);
    imagefilledrectangle($img, 0, 0, sizeof($data) / DETAIL, $height, imagecolorallocate($img, $r, $g, $b));

    // generate foreground transparency

    imagesavealpha($img, true);
    //set black for transparent color
    $white = imagecolorallocate($img, 255, 255, 255);
    for ($d = 0; $d < sizeof($data); $d += DETAIL) {
    // relative value based on height of image being generated
    // data values can range between 0 and 255
    $v = (int) ($data[$d] / 255 * $height);
    // draw the line on the image using the $v value and centering it vertically on the canvas
    $negative = imagecolortransparent($img, $white);
    imageline($img, $d / DETAIL, 0 + ($height – $v), $d / DETAIL, $height – ($height – $v), $negative);

    It would be great if someone can help me with it 🙂

    Tahnks and best regards

    • Andrew

      Hi Ruckus,

      I posted to the top of this blog entry that I created a transparency-capable version of the script — though it doesn’t stand out, so it’s easy to miss. The key lines of what I modified were:

      // create original image width based on amount of detail
      $img = imagecreatetruecolor(sizeof($data) / DETAIL, $height);

      // fill background of image
      if ($background == “”) {
      imagesavealpha($img, true);
      $transparentColor = imagecolorallocatealpha($img, 0, 0, 0, 127);
      imagefill($img, 0, 0, $transparentColor);
      } else {
      list($r, $g, $b) = html2rgb($background);
      imagefilledrectangle($img, 0, 0, sizeof($data) / DETAIL, $height, imagecolorallocate($img, $r, $g, $b));

      and then later, when re-sizing the image:

      // resample the image to the proportions defined in the form
      $rimg = imagecreatetruecolor($width, $height);
      // save alpha from original image
      imagesavealpha($rimg, true);
      imagealphablending($rimg, false);
      // …

      Hopefully that helps! It’s been a while since I’ve looked at/or touched this script, so that’s just off the top of my head.


      • Ruckus

        yeah, transparent background works. but this doesn’t work on my modfied foreground action 🙁

        see here:
        $negative = imagecolortransparent($img, $white);
        imageline($img, $d / DETAIL, 0 + ($height – $v), $d / DETAIL, $height – ($height – $v), $negative);

        but all in all i decided to use imagemagic to do this 😉

  29. Bruce

    Hi Andrew,

    Whenever I run it, it gives me the error “Error: WAV file not generated. Please verify directory write and execute permissions.”

    I’m still looking into it, but why does that error get thrown?

    • Andrew

      Hi Bruce,

      It sounds like some basic write/execute permissions problems just like the error indicates.

      If you are running the script from a Linux box, make sure the directory that the page is being called from has full write permissions to it (i.e. chmod 777 waveformdir where the script resides) since it copies the uploaded file to the current directory and performs all of the lame conversions (temporary files) to that same directory.

      If you’re running on a Windows box… well, to be honest, I can’t provide much help there as I don’t have so much experience playing around with read/write/execute permissions there, but the same idea as above applies.

      Alternatively, you can modify the script to copy the uploaded file to a directory you already know has write permissions and perform all of the lame conversions to that same directory.

      Hope that helps!


  30. […] some great comments in the original PHP MP3 Waveform Generator blog post, I decided to go ahead and do my best to optimize the script as much as possible. This […]

  31. Hi Andrew,
    Thanks for the script, me and Aaron (as mentioned) above have wrapped it up into a Drupal 6 module. You cad give it ago and upload files and annotate them with comments. It makes a soundcloud-like feature out of it except not requiring flash!
    Thanks again and theres a link back here from the code and site.

    Jowan & Aaron

  32. Peter Schmidler

    First of all thanks for the script! I also have a problem getting it working on OSX. I Get “Warning: unlink(0840747e99.mp3) [function.unlink]: No such file or directory” and I noticed that the file 0840747e99_o.mp3 is created and immediately deleted. The error Message points me to line 63 right after the exec(“lame … “). What could I do to solve this?
    Bst, Peter

    • Andrew

      Hi Peter,

      My first two initial guesses are:

      1) The directory you are running the script from lacks write permissions to copy/generate the temporary MP3/WAV file(s). Not sure about OSX, but open a terminal/console window, navigate to the script directory and try a `chmod 777 dirname` to allow full permissions; or

      2) Your lame command is not available from that directory. Make sure lame is installed onto your system. Open a terminal/console and navigate to the script directory and type `lame` into the terminal. You should see lame command line usage options and not “command not found” or anything like that.

      Give either of those a try and go from there. Let me know if you are still having issues and I’ll do my best to help you out.


      • Manish

        Thanks for every thing.

  33. Jelger

    How did you get it work on linux?

  34. You could also give a try. It runs on Linux and OS X (command line and GUI). It’s also pretty fast.

    — Benjamin

    • It’s a LOT faster and much more flexible. the PHP code needed for wav2png would not be much more than:

      shell_exec(‘wav2png –foreground-color=ffffffff –background-color=000000ff -o waveform.png input.wav’);

      Which would result in a white-on-black waveform. From this, Microsoft Windows doesn’t really seem like a flexible and open development/server environment… :-S

  35. […] Generating MP3 waveforms with PHP (by Andrew; 29 April 2010) […]

  36. Alessio

    Thank you very much! Works great on windows7/Apache 2.4.2/
    PHP 5.4.4

  37. Owen

    Hi Andrew, I’m trying to use this script, I’ve installed it on my local wamp install, dropped lame.exe and .dll inside the same dir as the .php script. I also added inside c:\windows\ incase.

    however on my wamp when i run it on chrome on a 3mb image, i just get a broken image icon.

    then when i run it on a live linux server i get a big black box with no waveforms inside of it,

    do you have any ideas?

    many thanks1

  38. […] php imagepng() generating black image only on server I am dynamically generating a waveform image from a user-uploaded sound file, using a script I’ve based on: […]

  39. the script you have given is not working on this website. all the requirements is installed. please give some info why it is not working??

  40. Hey Andrew,

    I love this script, it does exactly what I needed. And I’m sure you get tired of troubleshooting all of the different versions of it that people are using, so allow me to buy you a beer. But I’ve run into a really weird bug with it. It works fine on my development machine (IIS, PHP 5.2.11) but when I push it to my server (Ubuntu, PHP 5.3.2) it just generates a black image. I’ve made sure that I can read / write into the dirs for my wavs and for my generated images and that LAME is functioning. And I’m running out of rope here? Any ideas?

    • Andrew

      Hi Joe,

      Sorry for the delay in my response.

      It’s really difficult to say what the problem might be without having direct access to the script. My first suggestion for debugging would be to dump the output of the script to a readable text file and see if there are any errors at the top (before the binary image data is output). I might also check to see if the GD libraries on either server are the same version.

      My other thought is that I would try making sure that the MP3 file is being uploaded properly (try debugging with some var_dump(file_exists(…)) at the file handling portions of the script. Alternatively, I would also make sure that the MP3-to-WAV conversion portion of the script (using the lame commands) is giving you the same output on both the server and your dev box.

      Sorry that these are all very vague ideas, I’m just going over what my initial thought process would be in this situation.

      Hope this helps!

  41. Its only for WAMP server.. Working only in windows.

    How can i implement it on LAMP server (Linux) ?

    Thanks in Advance..


  42. Bryan

    Hi Andrew,

    Thanks this is really a big help for me, It’s perfectly working on my localhost
    on Windows 7

    But when i tried to test it on my web site(linux OS) its only print out a black image
    do you have any idea how do i fix this?

    Thanks in advanced!

  43. jc

    I’m really surprised no one is offering just a simple MP3 -> waveform image application/web application with aesthetic customization options. Seriously — google around and you’ll find that no one offers such service while there are a lot of people asking for just that on Yahoo Answers and various forum threads.

    There are people just looking for a way to turn their MP3s/WAVs into waveform images! Surely someone out there can help the less technically inclined among us. Personally, I’ve been on a hunt for a program that will render high resolution spectrographs of WAVs, but I haven’t found anything.

    I absolutely love Nugen Audio’s spectrogram (, but there’s no way to save the visual output as an image. I even contacted the developers, but the visualizer was created under contract, and can’t be modified.

    Surely there is something out there…

  44. Andrew

    Dear Andrew,

    thank you for the great work.
    I’ve run into a problem, which I think could be fixed pretty simply,
    if I had knowledge of php, which I don’t..
    I’ve uploaded the php file, and .dll and .exe of LAMB to my website (which is hosted by hostmonster),
    and when I try uploading a mp3 file on my website,
    it just generates a black rectangle image instead of waveform image.
    I’m sure this has been a frequently occurring problem for many others,
    but I’m not sure if it has been explained..
    I’ve made no modification to the file (since I don’t know php..).

    I greatly admire and applaud your work, and I will greatly appreciate it if you could help me out on this issue. Thanx.

    • Andrew

      I’ve learned that this is due to the fact that my website host doesn’t support the exec() function of php… Is there a workaround not to use any external program? 🙁

  45. Droid

    First of all thank you very much for the script.

    What i wanted to know was if i could make the waveform a bit bolder just like this example:

  46. khushwant

    Hi Andrew,

    Thanks for sharing this code snippets. But unfortunately I am not able to run it smoothly. Sometimes Images are creating very well but sometimes I am getting an image with 0 size. I have tried but not sure why the blank images are creating.

    I would appreciate if you can help me to point the reason why image is create of 0 size.


  47. Tom

    Hi Andrew,

    Thank you for great script. I am a beginner in PHP and I need help about warning that comes out during cript launch. I installed easy php on my PC which contains APACHE 2.4.4, MYSQL 5.6.11, PHP 5.4.14. Downloaded lame3.99.5 and followed the instruction in

    As I launched a script with mp3 file i get warnigs:

    As I launched a script with .wav file all worked fine.

    Could you tell me where the problem might be?


    • Tom

      Hi, I have found the problem. The upload_max_filesize was set up for 2MB and my WAV file was less than 2 MB and MP3 file was more then 2 MB. I changed the settings and now all works fine 😉

  48. john

    maybe this is a noob question but how to do it internally to get wave file for an mp3 file that exist on my website host (meaning without a post thing just i add the “nameofmp3file” on my webhost and then it do it)?

    Also wanted to ask does that work with wav files too?

    Last question is when i upload like a 1 minute mp3 file length, the wave image looks so small (so small) is there any way to make it bigger or wider?

    Thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>