Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
limikael committed Aug 12, 2013
1 parent a4e6446 commit 17e66cb
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
*.exe
*.out
*.app

build/*
.lock-waf*
.waf*
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "extern/ffsnd"]
path = extern/ffsnd
url = https://github.com/limikael/ffsnd.git
1 change: 1 addition & 0 deletions extern/ffsnd
Submodule ffsnd added at 646e79
106 changes: 106 additions & 0 deletions src/rendersound.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#include "soundrenderer.h"

/**
* Show help text.
*/
void printhelp() {
char *help=
"Usage: rendersound [options] <input> <output>\n"
"Renders the waveform of a sound file as a png image.\n"
"\n"
"Options:\n"
"\n"
" -h Show this help.\n"
" -y size Height in pixels of output.\n"
" -x size Width in pixels of output.\n"
" -s scale Set scale as pixels/sec.\n"
" This will cause -x to be ignored.\n"
" -c color Color expressed as rgb hex, e.g. 80ff80.\n"
" -f factor Set super sampling factor for anti aliasing.\n"
" Default is 4.\n"
" -p Show progress.\n"
"\n";

printf("%s",help);
exit(1);
}

/**
* Report progress.
*/
void progress(int percent) {
printf("\rProgress: %d%%",percent);
fflush(stdout);
}

/**
* Main.
*/
int main(int argc, char **argv) {
SOUNDRENDERER *soundrenderer;
char c;
unsigned int u;
int show_progress=0;
int res;

soundrenderer=soundrenderer_create();

while ((c=getopt(argc,argv,"hc:x:y:s:pf:")) != -1) {
switch (c) {
case 'c':
sscanf(optarg,"%x",&u);
soundrenderer_set_color(soundrenderer,u);
break;

case 'x':
soundrenderer_set_width(soundrenderer,atoi(optarg));
break;

case 'y':
soundrenderer_set_height(soundrenderer,atoi(optarg));
break;

case 's':
soundrenderer_set_pixels_per_sec(soundrenderer,atoi(optarg));
break;

case 'f':
soundrenderer_set_super_sample_factor(soundrenderer,atoi(optarg));
break;

case 'h':
printhelp();
exit(1);
break;

case 'p':
soundrenderer_set_progress_callback(soundrenderer,progress);
show_progress=1;
break;
}
}

if (argc-optind!=2) {
printf("Usage: rendersound [options] <infile> <outfile>\nTry rendersound -h for help.\n");
exit(1);
}

soundrenderer_set_output_file_name(soundrenderer,argv[optind+1]);
res=soundrenderer_render(soundrenderer,argv[optind]);

if (!res) {
printf("%s\n",soundrenderer_get_error(soundrenderer));
exit(1);
}

if (show_progress) {
progress(100);
printf("\n");
}

return 0;
}
258 changes: 258 additions & 0 deletions src/soundrenderer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include <gd.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
//#include <sndfile.h>
#include <stdbool.h>

#include "util.h"
#include "soundrenderer.h"
#include "ffsndin.h"
#include "ffsndutil.h"

struct SOUNDRENDERER {
FFSNDIN *ffsndin;

int width,height;
int unscaled_width,unscaled_height;
char *output_file_name;
int chunksize;
unsigned int color;
void (*progress_callback)(int);
int pixels_per_sec;
int super_sample_factor;

char *error_str;
};

/**
* Create a wav renderer.
*/
SOUNDRENDERER *soundrenderer_create() {
SOUNDRENDERER *rend;

rend=malloc(sizeof(SOUNDRENDERER));

if (!rend)
return NULL;

rend->height=50;
rend->width=500;
rend->output_file_name="out.png";
rend->chunksize=100;
rend->color=0xff0000;
rend->pixels_per_sec=0;
rend->progress_callback=NULL;
rend->super_sample_factor=4;

return rend;
}

/**
* Set super sampling factor.
*/
void soundrenderer_set_super_sample_factor(SOUNDRENDERER *soundrenderer, int factor) {
soundrenderer->super_sample_factor=factor;
}

/**
* Set progress callback.
*/
void soundrenderer_set_progress_callback(SOUNDRENDERER *rend, void (*callback)(int)) {
rend->progress_callback=callback;
}

/**
* Convert pixel to sample.
*/
int pixel_to_sample(SOUNDRENDERER* rend, int pix) {
return floor(pix*(long long)ffsndin_get_num_frames(rend->ffsndin)/rend->unscaled_width);
}

/**
* Dispose the soundrenderer.
*/
void soundrenderer_dispose(SOUNDRENDERER *rend) {
ffsndin_close(rend->ffsndin);
// sf_close(rend->sndfile);
free(rend);
}

/**
* Set output filename.
*/
void soundrenderer_set_output_file_name(SOUNDRENDERER *rend, char *fn) {
rend->output_file_name=fn;
}

/**
* Read peak values for a number of samples.
*/
void read_peaks(SOUNDRENDERER *rend, int samples, float *min, float *max) {
int i;
float vals[samples*ffsndin_get_num_channels(rend->ffsndin)];

if (!samples) {
*min=0;
*max=0;
return;
}

*min=1;
*max=-1;

ffsndin_read(rend->ffsndin,vals,samples);

for (i=0; i<samples*ffsndin_get_num_channels(rend->ffsndin); i++) {
if (vals[i]<*min)
*min=vals[i];

if (vals[i]>*max)
*max=vals[i];
}
}

/**
* Set color to use.
*/
void soundrenderer_set_color(SOUNDRENDERER *rend, unsigned int col) {
rend->color=col;
}

/**
* Set width.
*/
void soundrenderer_set_width(SOUNDRENDERER *rend, unsigned int width) {
rend->width=width;
}

/**
* Set pixels per sec.
*/
void soundrenderer_set_pixels_per_sec(SOUNDRENDERER *rend, unsigned int pixels_per_sec) {
rend->pixels_per_sec=pixels_per_sec;
}

/**
* Set height.
*/
void soundrenderer_set_height(SOUNDRENDERER *rend, unsigned int height) {
rend->height=height;
}

/**
* Allocate rgb.
*/
int allocate_rgb_color(gdImagePtr image, unsigned int rgb) {
int r=0xff&(rgb>>16);
int g=0xff&(rgb>>8);
int b=0xff&(rgb>>0);

return gdImageColorAllocate(image,r,g,b);
}

/**
* Get error.
*/
char *soundrenderer_get_error(SOUNDRENDERER *rend) {
return rend->error_str;
}

/**
* Render.
*/
int soundrenderer_render(SOUNDRENDERER *rend, char *fn) {
int pixel, position, next;
int y1, y2;
float min,max;
int col,transparentcol;
gdImagePtr image;
int percent, oldpercent;
int oldtime, t;

TRACE("running render..");

rend->error_str=NULL;
rend->ffsndin=ffsndin_open(fn);

if (!rend->ffsndin) {
rend->error_str="Unable to open input file.";
return 0;
}

if (rend->pixels_per_sec) {
int rate=ffsndin_get_samplerate(rend->ffsndin);
long frames=ffsndin_get_num_frames(rend->ffsndin);
rend->width=frames*rend->pixels_per_sec/rate;
}

/* TRACE("frames: %d",pragmasound_get_num_frames(rend->pragmasound));
TRACE("channels: %d",pragmasound_get_num_channels(rend->pragmasound));
TRACE("rate: %d",pragmasound_get_samplerate(rend->pragmasound));*/

rend->unscaled_width=rend->width*rend->super_sample_factor;
rend->unscaled_height=rend->height*rend->super_sample_factor;

image=gdImageCreateTrueColor(rend->unscaled_width,rend->unscaled_height);
gdImageAlphaBlending(image,false);
transparentcol=gdImageColorAllocateAlpha(image,255,0,0,127);
gdImageFilledRectangle(image,0,0,rend->unscaled_width,rend->unscaled_height,transparentcol);
gdImageAlphaBlending(image,true);

col=allocate_rgb_color(image,rend->color);
position=0;

oldpercent=0;
oldtime=time(NULL);

TRACE("WIDTH: %d",rend->width);

for (pixel=0; pixel<rend->unscaled_width; pixel++) {
percent=100*pixel/rend->unscaled_width;
t=time(NULL);
if (percent!=oldpercent /*&& t!=oldtime*/) {
if (rend->progress_callback)
rend->progress_callback(percent);
oldpercent=percent;
oldtime=t;
}
next=pixel_to_sample(rend,pixel+1);
read_peaks(rend,next-position,&min,&max);
position=next;

y1=round(rend->unscaled_height/2.0+rend->unscaled_height*min/2.0);
y2=round(rend->unscaled_height/2.0+rend->unscaled_height*max/2.0);

gdImageLine(image,pixel,y1,pixel,y2,col);
}

ffsndin_close(rend->ffsndin);

gdImagePtr scaled;
scaled=gdImageCreateTrueColor(rend->width,rend->height);

gdImageAlphaBlending(scaled,false);
transparentcol=gdImageColorAllocateAlpha(scaled,255,0,0,127);
gdImageFilledRectangle(scaled,0,0,rend->width,rend->height,transparentcol);
gdImageAlphaBlending(scaled,true);

gdImageCopyResampled(scaled,image, 0,0, 0,0,
rend->width,rend->height,
rend->unscaled_width,rend->unscaled_height);

FILE *out=fopen(rend->output_file_name,"wb");

if (!out) {
rend->error_str="Unable to open output file.";
return 0;
}

gdImageAlphaBlending(scaled,false);
gdImageSaveAlpha(scaled,true);
gdImagePng(scaled,out);
fclose(out);

return 1;
}
18 changes: 18 additions & 0 deletions src/soundrenderer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef __SOUNDRENDERER_H__
#define __SOUNDRENDERER_H__

typedef struct SOUNDRENDERER SOUNDRENDERER;

SOUNDRENDERER *soundrenderer_create();
void soundrenderer_dispose(SOUNDRENDERER *soundrenderer);
int soundrenderer_render(SOUNDRENDERER *soundrenderer, char *fn);
void soundrenderer_set_output_file_name(SOUNDRENDERER *soundrenderer, char *fn);
void soundrenderer_set_color(SOUNDRENDERER *soundrenderer, unsigned int col);
void soundrenderer_set_height(SOUNDRENDERER *soundrenderer, unsigned int height);
void soundrenderer_set_width(SOUNDRENDERER *soundrenderer, unsigned int width);
void soundrenderer_set_pixels_per_sec(SOUNDRENDERER *soundrenderer, unsigned int pixels_per_sec);
void soundrenderer_set_progress_callback(SOUNDRENDERER *soundrenderer, void (*callback)(int));
char *soundrenderer_get_error(SOUNDRENDERER *soundrenderer);
void soundrenderer_set_super_sample_factor(SOUNDRENDERER *soundrenderer, int factor);

#endif
Binary file added test/gm_soft.mp3
Binary file not shown.
Binary file added test/out.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added waf
Binary file not shown.
Loading

0 comments on commit 17e66cb

Please sign in to comment.