[PD-cvs] externals/pdp/scaf/pdp Makefile, 1.3, 1.4 pdp_ca.c, 1.4, 1.5 pdp_ca_system.c, 1.3, 1.4 scaf_feeder.s, 1.2, 1.3

Hans-Christoph Steiner eighthave at users.sourceforge.net
Fri Dec 16 02:05:39 CET 2005


Update of /cvsroot/pure-data/externals/pdp/scaf/pdp
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/scaf/pdp

Added Files:
	Makefile pdp_ca.c pdp_ca_system.c scaf_feeder.s 
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz

--- NEW FILE: pdp_ca.c ---
/*
 *   Pure Data Packet module for cellular automata
 *   Copyright (c) by Tom Schouten <pdp at zzz.kotnet.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */



#include "pdp_ca.h"
#include "pdp_internals.h"
#include <dlfcn.h>
#include <stdio.h>

t_class *pdp_ca_class;        // a cellular automaton processor: single input - single output
//t_class *pdp_ca2_class;     //                                 double input - single output
t_class *pdp_ca2image_class;   // converter from ca -> grey/yv12
t_class *pdp_image2ca_class;   // converter from grey/yv12 -> ca


// *********************** CA CLASS STUFF *********************


// this is defined in the makefile
// #define PDP_CA_RULES_LIB "/path/default.scafo"

#define PDP_CA_STACKSIZE 256
#define PDP_CA_MODE_1D 1
#define PDP_CA_MODE_2D 2

typedef struct pdp_ca_data_struct
{
    unsigned int env[2*4];
    unsigned int reg[2*4];
    unsigned int stack[2*PDP_CA_STACKSIZE];
    short int random_seed[4];
} t_pdp_ca_data;

typedef struct pdp_ca_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;
    int x_queue_id;

    /* double buffering data packets */
    int x_packet0;
    int x_packet1;

    /* some data on the ca_routine */
    void (*x_ca_routine)(void);
    void *x_ca_libhandle;
    char *x_ca_rulenames;
    int x_ca_nbrules;
    char ** x_ca_rulename;
    t_symbol *x_lastrule;
    
    /* nb of iterations */
    int x_iterations;

    /* shift ca on output */
    int x_horshift;
    int x_vershift;

    /* operation mode */
    int x_mode;
    int x_fullscreen1d;

    /* aligned vector data */
    t_pdp_ca_data *x_data;

    /* output packet type */
    t_symbol *x_packet_type;

} t_pdp_ca;


/* 1D: process from packet0 -> packet0 */
static void pdp_ca_process_ca_1D(t_pdp_ca *x)
{
    t_pdp *header = pdp_packet_header(x->x_packet0);
    unsigned int  *data   = (unsigned int *)pdp_packet_data  (x->x_packet0);

    int width  = pdp_type_ca_info(header)->width;
    int height = pdp_type_ca_info(header)->height;
    int i;

    unsigned int saved;

    /* load TOS in middle of buffer to limit the effect of stack errors */
    unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
    unsigned int *env = &x->x_data->env[0];
    unsigned int *reg = &x->x_data->reg[0];
    void *ca_routine = x->x_ca_routine;
    unsigned int rtos;

    /* double word width: number of unsigned ints per row  */
    int dwwidth = width >> 5;
    int currow = pdp_type_ca_info(header)->currow;

    unsigned long long result = 0;

    unsigned short temp;
    unsigned short *usdata;

    /* set destination row to 4th row from top (ca time horizon is 3 deep) */
    int dwrow0 = (((currow + height - 3) % height) * width) >> 5;
    int dwrow1 = (((currow + height - 2) % height) * width) >> 5;
    int dwrow2 = (((currow + height - 1) % height) * width) >> 5;
    int dwrow3 = (currow * width) >> 5;

    /* exit if there isn't a valid routine */
    if(!ca_routine) return;


    /* compute new row */
    for(i=0; i < (dwwidth-1) ; i+=1){
	env[0] = data[dwrow0 + i];
	env[1] = data[dwrow0 + i + 1];
	env[2] = data[dwrow1 + i];
	env[3] = data[dwrow1 + i + 1];
	env[4] = data[dwrow2 + i];
	env[5] = data[dwrow2 + i + 1];
	result = scaf_feeder(tos, reg, ca_routine, env);
	data[dwrow3 + i] = result & 0xffffffff;
    }
    // i == dwwidth-1
    
    /* compute last column in row */
    env[0] = data[dwrow0 + i];
    env[1] = data[dwrow0];
    env[2] = data[dwrow1 + i];
    env[3] = data[dwrow1];
    env[4] = data[dwrow2 + i];
    env[5] = data[dwrow2];
    result = scaf_feeder(tos, reg, ca_routine, env);
    data[dwrow3 + i] = result & 0xffffffff;


    /* undo the shift */
    usdata = (unsigned short *)(&data[dwrow3]);
    temp = usdata[(dwwidth*2)-1];
    for (i = (dwwidth*2 - 1); i > 0; i--){
	usdata[i] = usdata[i-1];
    }
    usdata[0] = temp;

    /* check data stack pointer */
    rtos = (unsigned int)tos;

    if (env[0] != rtos){
	if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
	if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
	x->x_ca_routine = 0;
	post("pdp_ca: rule disabled");
	
    }

    /* save current row */
    pdp_type_ca_info(header)->currow = (currow + 1) % height;

}


/* 2D: process from packet0 -> packet1 */
static void pdp_ca_process_ca_2D(t_pdp_ca *x)
{
    t_pdp *header0 = pdp_packet_header(x->x_packet0);
    t_pdp *header1 = pdp_packet_header(x->x_packet1);
    unsigned int  *data0   = (unsigned int *)pdp_packet_data  (x->x_packet0);
    unsigned int  *data1   = (unsigned int *)pdp_packet_data  (x->x_packet1);


    int width  = pdp_type_ca_info(header0)->width;
    int height = pdp_type_ca_info(header0)->height;
    int i,j;

    /* load TOS in middle of buffer to limit the effect of stack errors */
    unsigned int *tos = &x->x_data->stack[2*(PDP_CA_STACKSIZE/2)];
    unsigned int *env = &x->x_data->env[0];
    unsigned int *reg = &x->x_data->reg[0];
    void *ca_routine = x->x_ca_routine;
    unsigned int rtos;

    int offset = pdp_type_ca_info(header0)->offset;
    int xoffset = offset % width;
    int yoffset = offset / width;

    /* double word width: number of unsigned ints per row  */
    int dwwidth = width >> 5;

    unsigned long long result = 0;

    /* exit if there isn't a valid routine */
    if(!ca_routine) return;
    if(!header0) return;
    if(!header1) return;

    //post("pdp_ca: PRE offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);

    /* calculate new offset: lines shift up, rows shift left by 16 cells */
    xoffset = (xoffset + width - 16) % width;
    yoffset = (yoffset + height - 1) % height;

    offset =  yoffset * width + xoffset;

    //post("pdp_ca: PST offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);


    pdp_type_ca_info(header1)->offset = offset;


    for(j=0; j<dwwidth*(height - 2); j+=(dwwidth<<1)){
	for(i=0; i < (dwwidth-1) ; i+=1){
	    env[0] = data0[i + j];
	    env[1] = data0[i + j + 1];
	    env[2] = data0[i + j + dwwidth];
	    env[3] = data0[i + j + dwwidth + 1];
	    env[4] = data0[i + j + (dwwidth<<1)];
	    env[5] = data0[i + j + (dwwidth<<1) + 1];
	    env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
	    env[7] = data0[i + j + (dwwidth<<1) + dwwidth + 1];
	    result = scaf_feeder(tos, reg, ca_routine, env);
	    data1[i + j] = result & 0xffffffff;
	    data1[i + j + dwwidth] = result >> 32;
	}
	// i == dwwidth-1

	env[0] = data0[i + j];
	env[1] = data0[j];
	env[2] = data0[i + j + dwwidth];
	env[3] = data0[j + dwwidth];
	env[4] = data0[i + j + (dwwidth<<1)];
	env[5] = data0[j + (dwwidth<<1)];
	env[6] = data0[i + j + (dwwidth<<1) + dwwidth];
	env[7] = data0[j + (dwwidth<<1) + dwwidth];
	result = scaf_feeder(tos, reg, ca_routine, env);
	data1[i + j] = result & 0xffffffff;
	data1[i + j + dwwidth] = result >> 32;
    }

    // j == dwwidth*(height - 2)
    for(i=0; i < (dwwidth-1) ; i+=1){
	env[0] = data0[i + j];
	env[1] = data0[i + j + 1];
	env[2] = data0[i + j + dwwidth];
	env[3] = data0[i + j + dwwidth + 1];
	env[4] = data0[i];
	env[5] = data0[i + 1];
	env[6] = data0[i + dwwidth];
	env[7] = data0[i + dwwidth + 1];
	result = scaf_feeder(tos, reg, ca_routine, env);
	data1[i + j] = result & 0xffffffff;
	data1[i + j + dwwidth] = result >> 32;
    }
    // j == dwwidth*(height - 2)
    // i == dwwidth-1
    env[0] = data0[i + j];
    env[1] = data0[j];
    env[2] = data0[i + j + dwwidth];
    env[3] = data0[j + dwwidth];
    env[4] = data0[i];
    env[5] = data0[0];
    env[6] = data0[i + dwwidth];
    env[7] = data0[dwwidth];
    result = scaf_feeder(tos, reg, ca_routine, env);
    data1[i + j] = result & 0xffffffff;
    data1[i + j + dwwidth] = result >> 32;



    /* check data stack pointer */
    rtos = (unsigned int)tos;

    if (env[0] != rtos){
	if (env[0] > rtos) post("pdp_ca: ERROR: stack underflow detected in ca routine");
	if (env[0] < rtos) post("pdp_ca: ERROR: ca routine returned more than one item");
	x->x_ca_routine = 0;
	post("pdp_ca: rule disabled");
	
    }

    return;
}


static void pdp_ca_swappackets(t_pdp_ca *x)
{
   /* swap packets */
   int packet = x->x_packet1;
   x->x_packet1 = x->x_packet0;
   x->x_packet0 = packet;
}





/* tick advance CA one timestep */
static void pdp_ca_bang_thread(t_pdp_ca *x)
{
   int encoding;
   int packet;
   int i;
   int iterations =  x->x_iterations;
  
   /* invariant: the two packets are allways valid and compatible 
      so a bang is allways possible. this means that in the pdp an 
      invalid packet needs to be converted to a valid one */

   if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid");
   if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid");

   if (PDP_CA_MODE_2D == x->x_mode){
       for(i=0; i < iterations; i++){
      
	   /* process form packet0 -> packet1 */
	   pdp_ca_process_ca_2D(x);

	   /* swap */
	   pdp_ca_swappackets(x);
       }
   }
   else if (PDP_CA_MODE_1D == x->x_mode){
       if (x->x_fullscreen1d){
	   t_pdp *header0 = pdp_packet_header(x->x_packet0);
	   pdp_type_ca_info(header0)->currow = 0;
	   pdp_type_ca_info(header0)->offset = 0;
	   iterations = pdp_type_ca_info(header0)->height;
       }
       for(i=0; i < iterations; i++){
 
	   pdp_ca_process_ca_1D(x);
       }
   }

}

static void pdp_ca_sendpacket(t_pdp_ca *x)
{

    /* adjust offset before sending */
    t_pdp *header0 = pdp_packet_header(x->x_packet0);
    int offset, width, height, xoffset, yoffset, horshift, vershift;

    if (!header0) return;

    offset = pdp_type_ca_info(header0)->offset;
    width  = pdp_type_ca_info(header0)->width;
    height = pdp_type_ca_info(header0)->height;
    xoffset = offset % width;
    yoffset = offset / width;
    horshift = x->x_horshift;
    vershift = x->x_vershift;

    horshift %= width;
    if (horshift < 0) horshift += width;
    vershift %= height;
    if (vershift < 0) vershift += height;

    xoffset = (xoffset + horshift) % width;
    yoffset = (yoffset + vershift) % height;
    offset =  yoffset * width + xoffset;

    pdp_type_ca_info(header0)->offset = offset;



    /* output the packet */
    outlet_pdp(x->x_outlet0, x->x_packet0);
}

static void pdp_ca_bang(t_pdp_ca *x)
{
    /* we don't use input packets for testing dropping here 
       but check the queue_id to see if processing is
       still going on */
    
    if (-1 == x->x_queue_id){
	pdp_queue_add(x, pdp_ca_bang_thread, pdp_ca_sendpacket, &x->x_queue_id);
    }

    else{
	pdp_control_notify_drop(-1);
    }
}


/* this method stores the packet into x->x_packet0 (the packet
   to be processed) if it is valid. x->x_packet1 is not compatible
   it is regenerated so that it is 
   
   in short, when this routine returns both packets are valid
   and compatible.
*/


static void pdp_ca_copy_rw_if_valid(t_pdp_ca *x, int packet)
{
    t_pdp *header  = pdp_packet_header(packet);
    t_pdp *header1 = pdp_packet_header(x->x_packet1);


    int grabpacket;
    int convertedpacket;

    /* check if header is valid */
    if (!header) return;

    if (PDP_CA != header->type) return;
    if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return;


    /* packet is a ca, register it */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = pdp_packet_copy_rw(packet);


    /* make sure we have the right header */
    header = pdp_packet_header(x->x_packet0);


    /* make sure that the other packet is compatible */
    if ((pdp_type_ca_info(header1)->width != pdp_type_ca_info(header)->width) ||
	 (pdp_type_ca_info(header1)->height != pdp_type_ca_info(header)->height)) {

	/* if not, throw away and clone the new one */
	pdp_packet_mark_unused(x->x_packet1);
	x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
    }

    if (-1 == x->x_packet0) pdp_post("warning: packet 0 invalid");
    if (-1 == x->x_packet1) pdp_post("warning: packet 1 invalid");


};

/* hot packet inlet */
static void pdp_ca_input_0(t_pdp_ca *x, t_symbol *s, t_floatarg f)
{

    if (s == gensym("register_rw")){
	pdp_ca_copy_rw_if_valid(x, (int)f);
    }
    else if (s == gensym("process")){
	pdp_ca_bang(x);
    }


}

/* cold packet inlet */
static void pdp_ca_input_1(t_pdp_ca *x, t_symbol *s, t_floatarg f)
{

    if (s == gensym("register_rw"))
    {
	pdp_ca_copy_rw_if_valid(x, (int)f);
    }

}


static void pdp_ca_rule_string(t_pdp_ca *x, char *c)
{
    char tmp[256];
    void (*ca_routine)(void);


    /* check if we can find string */
    sprintf(tmp, "rule_%s", c);
    if (!(ca_routine = dlsym(x->x_ca_libhandle, tmp))){
	post("pdp_ca: can't fine ca rule %s (symbol: %s)", c, tmp);
	return;
    }
    /* ok, so store routine address */
    else{
	x->x_ca_routine = ca_routine;
	x->x_lastrule = gensym(c);
    }
}


static void pdp_ca_rule(t_pdp_ca *x, t_symbol *s)
{
    /* make sure lib is loaded */
    if (!x->x_ca_libhandle) return;
    
    /* set rule by name */
    pdp_ca_rule_string(x, s->s_name);
}

static void pdp_ca_rule_index(t_pdp_ca *x, t_float f)
{
    int i = (int)f;

    /* make sure lib is loaded */
    if (!x->x_ca_libhandle) return;

    /* check index */
    if (i<0) return;
    if (i>=x->x_ca_nbrules) return;

    /* set rule by index */
    pdp_ca_rule_string(x, x->x_ca_rulename[i]);

}


static void pdp_ca_close(t_pdp_ca *x)
{
    if (x->x_ca_libhandle){
	dlclose(x->x_ca_libhandle);
	x->x_ca_libhandle = 0;
	x->x_ca_routine = 0;
	if (x->x_ca_rulename){
	    free (x->x_ca_rulename);
	    x->x_ca_rulename = 0;
	}
    

    }
}


static void pdp_ca_printrules(t_pdp_ca *x)
{
    int i;

    if (!(x->x_ca_libhandle)) return;
    post("pdp_ca: found %d rules: ", x->x_ca_nbrules);
    for(i=0;i<x->x_ca_nbrules; i++) post("%3d: %s ", i, x->x_ca_rulename[i]);


}

/* open code library */
static void pdp_ca_openlib(t_pdp_ca *x, t_symbol *s)
{

    char *c;
    int words;

    /* close current lib, if one */
    pdp_ca_close(x);

    /* try to open new lib */
    if (!(x->x_ca_libhandle = dlopen(s->s_name, RTLD_NOW))){
	post("pdp_ca: can't open ca library %s\n%s", s->s_name, dlerror());
	x->x_ca_libhandle = 0;
	return;
    }

    /* scan for valid rules */
    if (!(x->x_ca_rulenames = (char *)dlsym(x->x_ca_libhandle, "rulenames"))){
	post("pdp_ca: ERROR: %s does not contain a name table. closing.", s->s_name);
        pdp_ca_close(x);
	return;
    }

    /* count rules */
    words = 0;
    for(c = (char *)x->x_ca_rulenames; *c;){
	words++;
	while(*c++);
    }
    x->x_ca_nbrules = words;
    x->x_ca_rulename = (char **)malloc(sizeof(char *) * words);

    /* build name array */
    words = 0;
    for(c = (char *)x->x_ca_rulenames; *c;){
	x->x_ca_rulename[words] = c;
	words++;
	while(*c++);
    }

    /* ok, we're done */
    post("pdp_ca: opened rule library %s", s->s_name ,x->x_ca_nbrules);

    /* print rule names */
    //pdp_ca_printrules(x);

    /* set last selected rule */
    pdp_ca_rule(x, x->x_lastrule);
  
    
}

/* compile source file and open resulting code library */
static void pdp_ca_opensrc(t_pdp_ca *x, t_symbol *s)
{
    #define TMPSIZE 1024
    char commandline[TMPSIZE];
    char library[TMPSIZE];
    int status;

    /*  setup compiler args */
    snprintf(library, TMPSIZE, "%so", s->s_name);
    snprintf(commandline, TMPSIZE, "scafc %s %s", s->s_name, library);



    /* call compiler */
    if (system(commandline)) 
    {
	post ("pdp_ca: error compiling %s", s->s_name);
    }
    else 
    {
	post("pdp_ca: compiled %s", s->s_name);
	pdp_ca_openlib(x, gensym(library));
    }
}

/* open a source file or a library, depending on extension */
static void pdp_ca_open(t_pdp_ca *x, t_symbol *s)
{
    char *name = s->s_name;
    char *end = name;
    while(*end) end++;
    if (end == name){
	post("pdp_ca: invalid file name");
	return;
    }
    /* if the name ends with 'o' assume it is a library */
    if (end[-1] == 'o'){
	pdp_ca_openlib(x, s);
    }
    /* otherwize, assume it is a source file */
    else{
	pdp_ca_opensrc(x, s);
    }

}

/* init the current packet with random noise */
static void pdp_ca_rand(t_pdp_ca *x){

    t_pdp *header = pdp_packet_header(x->x_packet0);
    short int *data = (short int *) pdp_packet_data(x->x_packet0);
    int i;

    int nbshortints = (pdp_type_ca_info(header)->width >> 4) * pdp_type_ca_info(header)->height;

    for(i=0; i<nbshortints; i++) 
	data[i] = random();
    
}


static void pdp_ca_newca(t_pdp_ca *x, t_float width, t_float height)
{
    /* delete old packets */
    pdp_packet_mark_unused(x->x_packet0);
    pdp_packet_mark_unused(x->x_packet1);


    /* create new packets */
    x->x_packet0 = pdp_packet_new_ca(PDP_CA, width, height);
    x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);

}


static void pdp_ca_iterations(t_pdp_ca *x, t_float f)
{
    int i = (int)f;

    if (i < 0) i = 0;

    x->x_iterations = i;
}

static void pdp_ca_horshift16(t_pdp_ca *x, t_float f)
{
    x->x_horshift = 16 * (int)f;
}

static void pdp_ca_vershift(t_pdp_ca *x, t_float f)
{
    x->x_vershift = (int)f;
}

static void pdp_ca_set1d(t_pdp_ca *x)
{
    x->x_mode = PDP_CA_MODE_1D;
}

static void pdp_ca_set2d(t_pdp_ca *x)
{
    x->x_mode = PDP_CA_MODE_2D;
}

static void pdp_ca_fullscreen1d(t_pdp_ca *x, t_floatarg f)
{
    if (f == 0.0f) x->x_fullscreen1d = 0;
    if (f == 1.0f) x->x_fullscreen1d = 1;
}

static void pdp_ca_free(t_pdp_ca *x)
{
    pdp_packet_mark_unused(x->x_packet0);
    pdp_packet_mark_unused(x->x_packet1);
    pdp_ca_close(x);
    free(x->x_data);
}



void *pdp_ca_new(void)
{
    t_pdp_ca *x = (t_pdp_ca *)pd_new(pdp_ca_class);

    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pdp"), gensym("pdp1"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("iterations"));

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_queue_id = -1;
    
    x->x_data = (t_pdp_ca_data *)malloc(sizeof(t_pdp_ca_data));
    x->x_ca_routine = 0;
    x->x_ca_libhandle = 0;
    x->x_ca_rulename = 0;

    x->x_horshift = 0;
    x->x_vershift = 0;

    pdp_ca_newca(x, 64, 64);
    pdp_ca_iterations(x, 1);
    pdp_ca_set2d(x);
    pdp_ca_fullscreen1d(x, 0);

    x->x_packet_type = gensym("grey");
    x->x_lastrule = gensym("gameoflife");
    pdp_ca_openlib(x, gensym(PDP_CA_RULES_LIB));

    return (void *)x;
}


// *********************** CA CONVERTER CLASSES STUFF *********************
// TODO: move this to a separate file later together with other converters (part of system?)

#define PDP_CA2IMAGE 1
#define PDP_IMAGE2CA 2

typedef struct pdp_ca_conv_struct
{
    t_object x_obj;
    t_float x_f;


    int x_threshold;

    int x_packet;

    t_outlet *x_outlet0;

    /* solve identity crisis */
    int x_whoami;

    /* output packet type */
    /* only greyscale for now */
    t_symbol *x_packet_type;

} t_pdp_ca_conv;

/* hot packet inlet */
static void pdp_ca_conv_input_0(t_pdp_ca_conv *x, t_symbol *s, t_floatarg f)
{
    int packet = -1;

    if (s == gensym("register_ro")){
	pdp_packet_mark_unused(x->x_packet);
	x->x_packet = pdp_packet_copy_ro((int)f);
	return;
    }
    else if (s == gensym("process")){
	switch(x->x_whoami){
	case PDP_CA2IMAGE:
	    packet = pdp_type_ca2grey(x->x_packet);
	    break;
	case PDP_IMAGE2CA:
	    packet = pdp_type_grey2ca(x->x_packet, x->x_threshold);
	    break;
	}
	
	/* throw away the original packet */
	pdp_packet_mark_unused(x->x_packet);
	x->x_packet = -1;


	/* pass the fresh packet */
	pdp_packet_pass_if_valid(x->x_outlet0, &packet);

	/* unregister the freshly created packet */
	//pdp_packet_mark_unused(packet);

	/* output if valid */
	//if (-1 != packet) outlet_pdp(x->x_outlet0, packet);
    }


}

void pdp_ca_conv_free(t_pdp_ca_conv *x) 
{
    pdp_packet_mark_unused(x->x_packet);
}


void pdp_image2ca_threshold(t_pdp_ca_conv *x, t_float f)
{
    f *= 0x8000;

    if (f < -0x7fff) f = -0x7fff;
    if (f > 0x7fff) f = 0x7fff;

    x->x_threshold = (short int)f;
}

void *pdp_ca2image_new(void)
{
    t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_ca2image_class);
    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 
    x->x_packet_type = gensym("grey");
    x->x_packet = -1;
    x->x_whoami = PDP_CA2IMAGE;
    return (void *)x;
}

void *pdp_image2ca_new(void)
{
    t_pdp_ca_conv *x = (t_pdp_ca_conv *)pd_new(pdp_image2ca_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("threshold"));
    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 
    x->x_packet_type = gensym("grey");
    x->x_packet = -1;
    x->x_whoami = PDP_IMAGE2CA;
    x->x_threshold = 0x4000;
    return (void *)x;
}


// *********************** CLASS SETUP FUNCTIONS *********************

#ifdef __cplusplus
extern "C"
{
#endif



void pdp_ca2image_setup(void)
{
    pdp_ca2image_class = class_new(gensym("pdp_ca2image"), (t_newmethod)pdp_ca2image_new,
    	(t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
    class_addmethod(pdp_ca2image_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
}

void pdp_image2ca_setup(void)
{
    pdp_image2ca_class = class_new(gensym("pdp_image2ca"), (t_newmethod)pdp_image2ca_new,
    	(t_method)pdp_ca_conv_free, sizeof(t_pdp_ca), 0, A_NULL);
    class_addmethod(pdp_image2ca_class, (t_method)pdp_ca_conv_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_image2ca_class, (t_method)pdp_image2ca_threshold, gensym("threshold"),  A_FLOAT, A_NULL);
}

void pdp_ca_setup(void)
{


    pdp_ca_class = class_new(gensym("pdp_ca"), (t_newmethod)pdp_ca_new,
    	(t_method)pdp_ca_free, sizeof(t_pdp_ca), 0, A_NULL);

   
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_iterations, gensym("iterations"), A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_bang, gensym("bang"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_printrules, gensym("rules"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_rand, gensym("random"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("ca"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_newca, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_horshift16, gensym("hshift16"), A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_vershift, gensym("vshift"), A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_close, gensym("close"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_openlib, gensym("openlib"),  A_SYMBOL, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_opensrc, gensym("opensrc"),  A_SYMBOL, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_open, gensym("open"),  A_SYMBOL, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule, gensym("rule"),  A_SYMBOL, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_rule_index, gensym("ruleindex"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_input_1, gensym("pdp1"), A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_set1d, gensym("1D"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_set2d, gensym("2D"), A_NULL);
    class_addmethod(pdp_ca_class, (t_method)pdp_ca_fullscreen1d, gensym("fullscreen1D"), A_FLOAT, A_NULL);

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_ca_system.c ---
/*
 *   Cellular Automata Extension Module for pdp - Main system code
 *   Copyright (c) by Tom Schouten <pdp at zzz.kotnet.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "pdp_ca.h"
#include "pdp_internals.h"

/* all symbols are C-style */
#ifdef __cplusplus
extern "C"
{
#endif


/* check if packet is a valid ca packet */
int pdp_packet_ca_isvalid(int packet)
{
    t_pdp *header = pdp_packet_header(packet);
    if (!header) return 0;
    if (PDP_CA != header->type) return 0;
    if (PDP_CA_STANDARD != pdp_type_ca_info(header)->encoding) return 0;

    return 1;
}


static t_pdp_symbol *pdp_packet_ca_get_description(int packet)
{
    t_pdp *header = pdp_packet_header(packet);
    char description[1024];
    char *c = description;
    int encoding;

    if (!header) return pdp_gensym("invalid");
    if (header->type == PDP_CA){
	c += sprintf(c, "ca");
	switch(pdp_type_ca_info(header)->encoding){
	case PDP_CA_STANDARD: c += sprintf(c, "/1bit2D"); break;
	default:
	    c += sprintf(c, "/unknown"); goto exit;
	}
	c += sprintf(c, "/%dx%d", 
		     pdp_type_ca_info(header)->width, 
		     pdp_type_ca_info(header)->height);

    exit:
	return pdp_gensym(description);
    } 
    else return pdp_gensym("unknown");
}

/* create a new ca packet */
int pdp_packet_new_ca(int encoding, int width, int height)
{
    int p;
    int w = (int)width;
    int h = (int)height;
    int bytesize;
    t_pdp *header;

    /* ensure with = multiple of 64 */
    w &= 0xffffffc0;

    /* ensure height = multiple of 4 */
    w &= 0xfffffffc;

    w = (w<64) ? 64 : w;
    h = (h<4) ? 4 : h;

    bytesize = (w>>3) * h;


    /* create new packets */
    p = pdp_packet_new(PDP_CA, bytesize);
    header = pdp_packet_header(p);
    if (!header) {
	pdp_post("error: can't create CA packet");
	return -1;
    }

    pdp_type_ca_info(header)->encoding = PDP_CA_STANDARD;
    pdp_type_ca_info(header)->width = w;
    pdp_type_ca_info(header)->height = h;
    pdp_type_ca_info(header)->offset = 0;
    pdp_type_ca_info(header)->currow = 0; /* only used for 1D ca */
    pdp_type_ca_info(header)->currow = 0;
    header->desc = 0;
    header->desc = pdp_packet_ca_get_description(p);
    //post("creating %s", header->desc->s_name);
    return p;
   
}


/* convert a CA packet to greyscale */

inline void _pdp_type_ca2grey_convert_word(unsigned short int source, short int  *dest)
{

    int i;
    for (i = 15; i>=0; i--){
	dest[i] =  ((unsigned short)(((short int)(source & 0x8000)) >> 14)) >> 1;  
	source <<= 1;
    }
}

int pdp_type_ca2grey(int packet)
{
    int w, h, s, x, y, srcindex;
    long long offset, xoffset, yoffset;
    short int *dest;
    unsigned short int *source;
    t_pdp *header;
    t_pdp *newheader;
    int newpacket;
    if (!(pdp_packet_ca_isvalid(packet))) return -1;

    header = pdp_packet_header(packet);
    w = pdp_type_ca_info(header)->width;
    h = pdp_type_ca_info(header)->height;
    s = w*h;
    source = (unsigned short int *)pdp_packet_data(packet);
    offset = pdp_type_ca_info(header)->offset;
    yoffset = (offset / w) * w;
    xoffset = offset % w;

    //post("pdp_type_ca2grey: offset: %d, xoffset: %d, yoffset: %d", offset, xoffset, yoffset);

    newpacket = pdp_packet_new_image_grey(w, h);
    newheader = pdp_packet_header(newpacket);

    if (!newheader) return -1;

    //newheader->info.image.width = w;
    //newheader->info.image.height = h;
    //newheader->info.image.encoding = PDP_IMAGE_GREY;
    dest = (short int *)pdp_packet_data(newpacket);


#define check_srcindex \
if (srcindex >= (s >> 4)) post ("pdp_type_ca2grey: srcindex out of bound");

#define check_dstindex \
if ((x+y) >= s) post ("pdp_type_ca2grey: dstindex out of bound");


    /* debug : dont' shift offset 
    if (0){
       for(y=0; y< (h*w); y+=w){
          for(x=0; x<w; x+=16){
	    _pdp_type_ca2grey_convert_word (source[(x+y)>>4],  &dest[x+y]);
	  }
       }
       return newpacket;
    }
    */

    /* create top left */
    for (y=0; y < (h*w) - yoffset; y+=w) { 
	for (x=0; x< (w - xoffset); x+=16) {
	    srcindex = (x+xoffset + y+yoffset) >> 4;
	    //check_srcindex;
	    //check_dstindex;
	    _pdp_type_ca2grey_convert_word (source[srcindex],  &dest[x+y]);
	}
    }
	    
    /* create top right */
    for (y=0; y < (h*w) - yoffset; y+=w) { 
	for (x = (w - xoffset); x < w; x+=16) {
	    srcindex = (x+xoffset-w + y+yoffset) >> 4;
	    //check_srcindex;
	    //check_dstindex;
	    _pdp_type_ca2grey_convert_word (source[srcindex],  &dest[x+y]);
	}
    }
	    
    /* create bottom left */
    for (y=(h*w) - yoffset; y < h*w; y+=w) { 
	for (x=0; x< (w - xoffset); x+=16) {
	    srcindex = (x+xoffset + y+yoffset-(w*h)) >> 4;
	    //check_srcindex;
	    //check_dstindex;
	    _pdp_type_ca2grey_convert_word (source[srcindex],  &dest[x+y]);
	}
    }
	    
    /* create bottom right */
    for (y=(h*w) - yoffset; y < h*w; y+=w) { 
	for (x = (w - xoffset); x < w; x+=16) {
	    srcindex = (x+xoffset-w + y+yoffset-(w*h)) >> 4;
	    //check_srcindex;
	    //check_dstindex;
	    _pdp_type_ca2grey_convert_word (source[srcindex],  &dest[x+y]);
	}
    }
	    

    return newpacket;

}


inline unsigned short int _pdp_type_grey2ca_convert_word(short int  *src, short int threshold)
{
    short int tmp;
    short int dest = 0;
    int i;

    for (i = 15; i >= 0; i--){
	dest <<= 1;
	dest |= (src[i] > threshold);
    }

    return dest;
}



int pdp_type_grey2ca(int packet, short int threshold)
{
    int w, h, s, x, y, srcindex;
    long long offset, xoffset, yoffset;
    short int *dest;
    short int *source;
    t_pdp *header;
    t_pdp *newheader;
    int newpacket;
    if (!(pdp_packet_image_isvalid(packet))) return -1;

    header = pdp_packet_header(packet);
    w = header->info.image.width;
    h = header->info.image.height;
    s = w*h;
    source = (unsigned short int *)pdp_packet_data(packet);

    if ( (PDP_IMAGE_GREY != header->info.image.encoding)
	 && (PDP_IMAGE_YV12 != header->info.image.encoding)) return -1;

    newpacket = pdp_packet_new_ca(PDP_CA_STANDARD, w, h);
    newheader = pdp_packet_header(newpacket);

    if (!newheader) return -1;

    dest = (short int *)pdp_packet_data(newpacket);

    for(y=0; y< (h*w); y+=w){
	for(x=0; x<w; x+=16){
	    dest[(x+y)>>4] = _pdp_type_grey2ca_convert_word (&source[x+y], threshold);
	}
    }
    return newpacket;


}

/* returns a pointer to the ca subheader given the pdp header */
t_ca *pdp_type_ca_info(t_pdp *x){return (t_ca *)(&x->info.raw);}


void pdp_ca_setup(void);
void pdp_ca2image_setup(void);
void pdp_image2ca_setup(void);


static int _ca_to_image(int packet, t_pdp_symbol *template)
{
    return pdp_type_ca2grey(packet);
}

static int _image_to_ca(int packet, t_pdp_symbol *template)
{
    // convert with default threshold == 0.5
    return pdp_type_grey2ca(packet, 0.5f);
}

void pdp_scaf_setup(void)
{

    t_pdp_conversion_program *program;

    /* babble */
    post ("PDP: pdp_scaf extension library");

    /* setup modules */
    pdp_ca_setup();
    pdp_ca2image_setup();
    pdp_image2ca_setup();

    /* setup type conversion */
    program = pdp_conversion_program_new(_ca_to_image, 0);
    pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/*/*"), program);
    pdp_type_register_conversion(pdp_gensym("ca/*/*"), pdp_gensym("image/grey/*"), program);

    program = pdp_conversion_program_new(_image_to_ca, 0);
    pdp_type_register_conversion(pdp_gensym("image/grey/*"), pdp_gensym("ca/*/*"), program);


   
    
}




#ifdef __cplusplus
}
#endif

--- NEW FILE: Makefile ---
current: all_modules

include ../Makefile.config

OBJECTS = pdp_ca.o pdp_ca_system.o scaf_feeder.o


all_modules: $(OBJECTS) 

clean:
	rm -f *~
	rm -f *.o


--- NEW FILE: scaf_feeder.s ---
#     Pure Data Packet - scaf feeder routine.
#    Copyright (c) by Tom Schouten <pdp at zzz.kotnet.org>
# 
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
# 
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
# 
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

# for dup
.include "../compiler/scafmacro.s"


# *rg is only used for returning the stack pointer
# the 4 bit counter is using registers mm4-mm7 now
# long long scaf_feeder(void *tos, void *rg, *void() ca_rule, void *env)
.globl scaf_feeder
.type scaf_feeder, @function
scaf_feeder:	
	pushl %ebp
	movl %esp, %ebp
	push %esi
	push %edi
	
	movl 20(%ebp), %edi	# load env ptr
	movl 8(%ebp), %esi	# load TOS2 ptr
	movl 16(%ebp), %eax	# address of ca routine
	pcmpeqw %mm3, %mm3	# load 1 reg

	call *%eax		# TOS = 32x2 cell result
	dup			# push %mm0 to memory
	movl (%esi), %eax
	movl 4(%esi), %edx
	lea 16(%esi), %esi	# discard stack
	movl %esi, (%edi)	# store for stack underflow check

	emms
	pop %edi
	pop %esi
	leave
	ret





More information about the Pd-cvs mailing list