Press here to show the print version.

 


/*-
 * Copyright (c) 2006 Hans Petter Selasky. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *
 * image_sound.c - A program for making sound from pictures
 *
 * History:
 *
 * Tue Apr 11 15:52:13 CEST 2006:
 *   Fixed a small bug.
 *
 * Wed Apr 12 11:23:04 CEST 2006
 *   Added support for logarithmic frequency scale.
 *
 * Wed Apr 12 21:09:21 CEST 2006
 *   Fixed a small bug.
 *
 * This program outputs raw 22100Hz 16-bit signed audio.
 */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>

/*
 *
 * If one has got the SOX package installed, the following commands may
 * be helpful under UNIX:
 *
 * ./image_sound -n 0 | play -c 1 -f s -t raw -r 22100 -s w /dev/fd/0
 * ./image_sound -n 4 | sox -t raw -r 22100 -s -w -c 1 /dev/fd/0 test.wav
 *
 */

#define D(x) ((double)(x))

#if 1
#define WINDOW_SIZE 256 /* requires 200MHz CPU at least */
#else
#define WINDOW_SIZE 128 /* requires 40MHz CPU at least */
#endif

#define IMAGE_SIZE_Y 256

#define SAMPLE_FREQ   22100 /* Hz */
#define  SCALE_FREQ   ((SAMPLE_FREQ+0.0) / ((WINDOW_SIZE/2)+0.0))
#define    LOW_FREQ   (500.0 / SCALE_FREQ) /* Hz */
#define   HIGH_FREQ   (5000.0 / SCALE_FREQ) /* Hz */

#define BANDWIDTH_LOG     800 /* relative to 1000 */
#define BANDWIDTH_LIN     975 /* relative to 1000 */

#define PRIME 0xffff1d /* a special prime number */

#define GET_PIXEL(p,x,y) ((p).pixel_data[((p).width * (y) *		\
					  (p).bytes_per_pixel) +	\
					 ((p).bytes_per_pixel * (x))])
/*
 * The following image files, 256x256xRGB, 
 * were created using GIMP 2.x, by 
 * selecting "Save as" "C source code"
 */

#ifndef HAVE_IMAGE
#include "my_image00.c"
#endif

static int32_t
get_white_noise(void)
{
    static u_int32_t white_noise_rem = 1;
    u_int32_t temp;

    if (white_noise_rem & 1) {
        white_noise_rem += PRIME;
    }
    white_noise_rem /= 2;
    temp = white_noise_rem;

    temp ^= 0x800000; /* signed to unsigned conversion */
    if(temp & 0x800000) {
        temp |= (-0x800000); /* sign extension */
    }
    return temp;
}

static void
print_sample(int16_t out)
{
    printf("%c%c", out & 0xFF, (out >> 8) & 0xFF);
    return;
}

/*
 * the following routine is 
 * a classic FIR filter that
 * filters the noise
 */
static double
filter_00(double *factor)
{
    static double func[WINDOW_SIZE] = { /* zero */ };
    static u_int16_t pos;
    double temp = 0.0;
    u_int32_t x;

    func[pos] = get_white_noise() / 512;

    pos++;
    if(pos >= WINDOW_SIZE) {
       pos = 0;
    }

    for(x = WINDOW_SIZE; x--; )
    {
        temp += 
	  factor[x] * 
	  func[(pos+(WINDOW_SIZE-1)-x) % WINDOW_SIZE];
    }
    return temp;
}

static void
low_pass(double freq, double amp, double *factor)
{
    int32_t x, z;

    freq -= ((int32_t)(freq / D(WINDOW_SIZE/4))) * (WINDOW_SIZE/4);

    z = (D(D(WINDOW_SIZE/2) / (2.0*freq)) * D((int32_t)(2.0*freq)));

    if(z < 0) {
       z = -z;
    }

    if(z > (WINDOW_SIZE/2)) {
       z = (WINDOW_SIZE/2);
    }

    factor[(WINDOW_SIZE/2)] += (2.0 * amp * freq) / D(WINDOW_SIZE/2);

    freq *= (2.0*M_PI) / D(WINDOW_SIZE/2);

    for(x = -z+1; x < z; x++)
    {
        if(x != 0) {
          factor[(x + (WINDOW_SIZE/2))] += (amp * sin(freq * D(x))) / (M_PI*D(x));
        }
    }
    return;
}

static void
high_pass(double freq, double amp, double *factor)
{
    /* NOTE: freq must be negative */

    factor[WINDOW_SIZE/2] += 1.0*amp;

    low_pass(-freq, amp, factor); /* high-pass */

    return;
}

static void
band_pass(double freq_a, double freq_b, double amp, double *factor)
{
    low_pass(freq_b, amp, factor); /* lowpass */
    low_pass(-freq_a, amp, factor); /* highpass */

    return;
}

static void
band_stop(double freq_a, double freq_b, double amp, double *factor)
{
    factor[WINDOW_SIZE/2] += 1.0*amp;

    low_pass(-freq_b, amp, factor); /* lowpass */
    low_pass(freq_a, amp, factor); /* highpass */

    return;
}

static struct {
  double factor[WINDOW_SIZE];
} bp_data[IMAGE_SIZE_Y] = { /* zero */ };

int main(int argc, char **argv)
{
    double factor_temp[WINDOW_SIZE] =  { /* zero */ };
    double factor_curr[WINDOW_SIZE] =  { /* zero */ };
    double factor_last[WINDOW_SIZE] =  { /* zero */ };
    double f;
    double df;
    double bw;
    double amp;
    double *f_ptr;

    u_int32_t x,y,z,t,u;
    u_int32_t repeat = 0; /* forever */
    u_int32_t bandwidth = 0;
    u_int8_t logarithmic = 0;

    while(argc--)
    {
        if((argc >= 1) && 
	   (strcmp(argv[0], "-n") == 0))
	{
            repeat = atoi(argv[1]);
	}

        if((argc >= 1) && 
	   (strcmp(argv[0], "-b") == 0))
	{
            bandwidth = atoi(argv[1]);
	}

	if(strcmp(argv[0], "-l") == 0)
	{
	    logarithmic = 1;
	}
        argv++;
    }

    if(bandwidth == 0)
    {
        bandwidth = logarithmic ? BANDWIDTH_LOG : BANDWIDTH_LIN;
    }

    if(logarithmic)
    {
        f = D(HIGH_FREQ);
	df = pow(D(HIGH_FREQ) / D(LOW_FREQ),
		 1.0 / D(IMAGE_SIZE_Y));
	bw = D(bandwidth)/D(1000);

        for(x = 0; x < IMAGE_SIZE_Y; x++)
	{
	    /* limit the bandwidth used by each pixel */
	    band_pass(f, (f * df * bw), (1.0 - bw) * 0.5,
		      &bp_data[x].factor[0]);
	    f /= df;
	}
    }
    else
    {
        f = HIGH_FREQ;
	df = (HIGH_FREQ-LOW_FREQ) / (IMAGE_SIZE_Y + 0.0);
	bw = D(bandwidth)/D(1000);

        /* initialize tables */

        for(x = 0; x < IMAGE_SIZE_Y; x++)
	{
	    /* limit the bandwidth used by each pixel */
	    band_pass(f, f+ (df * bw), 1.0,
		      &bp_data[x].factor[0]);
	    f -= df;
	}
    }

    /* generate sound */

    y = 0;
    x = 0;
    u = SAMPLE_FREQ/(WINDOW_SIZE/2);

    while(1)
    {
      if(y == 0)
      {
	 y = u;

	 x++;
	 if(x >= WINDOW_SIZE) {
	    x = 0;

	    if((repeat) && (!--repeat))
	    {
	        return 0;
	    }
	 }

	 bcopy(factor_curr, factor_last, sizeof(factor_last));

	 bzero(factor_curr, sizeof(factor_curr));

	 for(z = 0; z < IMAGE_SIZE_Y; z++)
	 {
	     f = GET_PIXEL(gimp_image,x*(256/WINDOW_SIZE),z*(256/IMAGE_SIZE_Y)) / 512.0;
	     f_ptr = &bp_data[z].factor[0];

#ifdef DEBUG
	     printf("%c", (f == 0.0) ? '.' : '#');
#endif
	     for(t = 0; t < WINDOW_SIZE; t++)
	     {
	         factor_curr[t] += f * f_ptr[t];
	     }
	 }
#ifdef DEBUG
	 printf("\n");
#endif
      }
      else
      {
	 y--;
      }

      f = D(y) / D(u);

      for(t = 0; t < WINDOW_SIZE; t++)
      {
	  factor_temp[t] = (f * factor_last[t]) + ((1-f)*factor_curr[t]);
      }

#ifndef DEBUG
      print_sample(filter_00(&factor_temp[0]));
#endif
    }

    return 0;
}


This document was last updated on Fri 23 Sep 14:00:52 CEST 2022.