Hi

I'm writing my second external, an arpeggiator called "arp". I know I was encouraged to write it as an abstraction, but the exact features that I wanted seemed too overwhelming for a pd-newbie.

Anyways, I have two questions:

1) Whenever I instantiate it in pd I get "consistency check failed: class_addmethod: arp_bang: bad argument types" in the pd console. However the external seems to work just fine. If someone clever could look at the code an spot the mistake, I'd be most happy! Basically I have four float-inlets where the first should also accept "bang"-messages.

2) With the recent thread on name space in mind, is there anything I should do to make it more name-space-safe? Of course I could prepend it with something like my name, but that would be so ugly :-)

NB: I'll make a proper announcement/release when it's finished and supplied with a -help.pd file.

--
peace, love & harmony
Atte

http://atte.dk       | http://myspace.com/attejensen
http://anagrammer.dk | http://atte.dk/compositions
/*
  Arpeggio external, Atte André Jensen, 2007
  
  This code is released under GPL
*/
#include <m_pd.h>
#include <stdlib.h>
#include <time.h>
#define NB_ELEMENTS 200
static t_class *arp_class;

typedef struct _arp {
    t_object  x_obj;
    t_int nb_elements, direction;
    t_float notes[NB_ELEMENTS];
    t_int velocities[NB_ELEMENTS];
    //t_int current_pos, current_direction;
    t_float current_note, current_velocity, last_note, last_velocity, tmp;
    t_float note, velocity, mode, octaves;
    t_inlet *note_in, *velocity_in;
    t_outlet *note_out, *velocity_out;
} t_arp;


void arp_bang(t_arp *x) {
    t_float note, best_note, delta, best_delta;
    t_int octave, index;
    t_int random_number;

    //post("inside arp_bang");
    //post("x->mode: %f",x->mode);

    if(x->nb_elements == 0){
	return;
    }

    if(x->mode >= 0 && x->mode <= 3){
	if(x->current_note >= 0){
	    // send noteoff for sounding note
	    outlet_float(x->note_out, x->current_note);
	    outlet_float(x->velocity_out, 0);
	}

	best_delta = 1000 * -1 * x->direction;
	best_note = x->current_note;
	if(x->direction == 0){
	    // first time arround, different for each mode
	    if(x->mode == 0 || x->mode == 2){
		x->current_note = x->notes[0];
		x->current_velocity = x->velocities[0];
		x->direction = 1;
	    } else if(x->mode == 1 || x->mode == 3){
		x->current_note = x->notes[x->nb_elements - 1] + ((x->octaves -1)* 12);
		x->current_velocity = x->velocities[x->nb_elements - 1];
		x->direction = -1;
	    }
	} else {
	    for(octave = 0; octave < x->octaves; octave++){
		for(index = 0; index < x->nb_elements; index++){
		    note = x->notes[index] + 12 * octave;
		    delta = x->current_note - note;
		    //post("index:%i, octave:%i, note:%f, delta:%f",index, octave, note, delta);
		    if((x->direction > 0 && delta < 0 && delta > best_delta) ||
		       (x->direction < 0 && delta > 0 && delta < best_delta)){
			best_delta = delta;
			x->last_velocity = x->current_velocity;
			x->current_velocity = x->velocities[index];
			best_note = note;
			//post("delta::%f, best_delta: %f, note: %f, best_note:%f", delta, best_delta, note, best_note);
		    }
		}
	    }
	    if(best_note == x->current_note && x->nb_elements > 1){
		//post("at the end");
		// at the end
		if(x->mode == 0){
		    //post("mode 0");
		    x->current_note = x->notes[0];
		    x->current_velocity = x->velocities[0];
		} else if (x->mode == 1){
		    //post("mode 1");
		    x->current_note = x->notes[x->nb_elements - 1] + ((x->octaves -1)* 12);
		    x->current_velocity = x->velocities[x->nb_elements - 1];
		} else if(x->mode == 2 || x->mode == 3){
		    //post("mode 2/3");
		    x->tmp = x->current_note;
		    x->current_note = x->last_note;
		    x->last_note = x->tmp;
		    
		    x->tmp = x->current_velocity;
		    x->current_velocity = x->last_velocity;
		    x->last_velocity = x->tmp;
		    
		    x->direction = -1 * x->direction;
		}
		//post("end of switch if, x->current_note:%f, x->last_note:%f",x->current_note,x->last_note);
	    } else {
		x->last_note = x->current_note;
		x->current_note = best_note;
	    }
	}
	outlet_float(x->note_out, x->current_note);
	outlet_float(x->velocity_out, x->current_velocity);
    } else if(x->mode == 4){
	// random
	//post("mode:4");
	
	random_number = rand();
	
	index = random_number%x->nb_elements;
	octave = random_number%(int)x->octaves;
	/*
	post("random index:%i",index);
	post("random octave:%i",octave);
	*/
	x->current_note = x->notes[index] + 12 * octave;
	x->current_velocity = x->velocities[index];
	
	outlet_float(x->note_out, x->current_note);
	outlet_float(x->velocity_out, x->current_velocity);

    } else {
	//post("unknown mode");
    }
    
}

void arp_float(t_arp *x, t_floatarg f1) {
    //post("inside arp_float");
    int i;
    int found = -1;
    //t_float max = 0, min = 100000;
    int pos = 0;
    
    x->note = f1;

    //post("note:%f,velocity:%f",x->note,x->velocity);

    //post("max:%f, min:%f",max, min);
    if(x->velocity != 0){
	for(i=0; i<=x->nb_elements; i++){
	    // find position for new note
	    if(x->notes[i] == f1){
		pos = -1;
		i = x->nb_elements;
	    }
	    else if(x->notes[i] > x->note){
		pos = i;
		i = x->nb_elements;
	    } else {
		pos = i;
	    }
	}
	if(pos >= 0){
	    x->nb_elements++;
	    for(i=x->nb_elements; i>=pos; i--){
		x->notes[i] =x->notes[i-1];
		x->velocities[i] =x->velocities[i-1];
	    }
	    x->notes[pos] = x->note;
	    x->velocities[pos] = x->velocity;
	}
    } else {
	pos = -1;
	for(i=0; i<x->nb_elements; i++){
	    // find position for new note
	    if(x->notes[i] == f1){
		pos = i;
		i = x->nb_elements;
	    }
	}
	if(pos >= 0){
	    x->nb_elements--;
	    for(i=pos; i<=x->nb_elements; i++){
		x->notes[i] =x->notes[i+1];
		x->velocities[i] =x->velocities[i+1];
	    }
	}
	
    }

    /*
      if(x->velocity != 0){
      post("noteon...");
      } else {
      post("noteoff...");

      }
    */

    /*
      post("nb_elements:%i",x->nb_elements);
      post("%f %f %f %f %f %f %f %f %f %f",
      x->notes[0],
      x->notes[1],
      x->notes[2],
      x->notes[3],
      x->notes[4],
      x->notes[5],
      x->notes[6],
      x->notes[7],
      x->notes[8],
      x->notes[9]
      );
      post("%i %i %i %i %i %i %i %i %i %i",
      x->velocities[0],
      x->velocities[1],
      x->velocities[2],
      x->velocities[3],
      x->velocities[4],
      x->velocities[5],
      x->velocities[6],
      x->velocities[7],
      x->velocities[8],
      x->velocities[9]
      );
    */
}



void arp_velocity(t_arp *x, t_floatarg f1) {
    x->velocity = f1;
}

void arp_mode(t_arp *x, t_floatarg f1) {
    if(f1 >= 0 && f1 <= 4){
	x->mode = f1;
    } else {
	post("[arp]: mode out of range (0-3)");
    }
    //post("x->mode:%f",x->mode);
}

void arp_octaves(t_arp *x, t_floatarg f1) {
    if(f1 >= 1 && f1 <= 10){
	x->octaves = f1;
    } else {
	post("[arp]: octave out of range (1-10)");
    }
    //post("x->octaves:%f",x->octaves);
}


//void *arp_new(t_floatarg f) {
void *arp_new(t_symbol *s, int argc, t_atom *argv){
    //post("inside new");
    t_float mode, octaves;
    t_arp *x = (t_arp *)pd_new(arp_class);

    // seed random
    srand(time(0));

    inlet_new(&x->x_obj, &x->x_obj.ob_pd,
	      gensym("float"), gensym("velocity"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd,
	      gensym("float"), gensym("mode"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd,
	      gensym("float"), gensym("octaves"));
    
    x->note_out = outlet_new(&x->x_obj, &s_float);
    x->velocity_out = outlet_new(&x->x_obj, &s_float);

    mode = atom_getfloat(argv);
    x->mode = 0;
    //x->current_pos = -1;
    x->current_note = -1;
    x->direction = 0;
    //post("argc:%i",argc);
    if(argc > 0){
	if(mode >=0 && mode <=4){
	    x->mode = mode;
	} else {
	    post("[arp]: mode out of range (0-3)");
	}
    }
    
    octaves = atom_getfloat(argv+1);
    x->octaves = 1;
    //post("argc:%i",argc);
    if(argc > 1){
	if(octaves >=1 && octaves <=10){
	    x->octaves = octaves;
	} else {
	    post("[arp]: octaves out of range (0-2)");
	}
    }
    
    //post("mode:%f",x->mode);
    //post("octaves:%f",x->octaves);
    return (void *)x;
}

void arp_setup(void) {
    //post("inside arp_setup");
    arp_class = class_new(gensym("arp"),
			  (t_newmethod)arp_new,
			  0, sizeof(t_arp),
			  CLASS_DEFAULT,
			  A_GIMME, 0);

    class_addbang  (arp_class, arp_bang);
    class_addfloat  (arp_class, arp_float);

    class_addmethod(arp_class,
		    (t_method)arp_velocity, gensym("velocity"),
		    A_DEFFLOAT, 0);
    class_addmethod(arp_class,
		    (t_method)arp_bang, gensym("bang"),
		    A_DEFFLOAT, 0);
    class_addmethod(arp_class,
		    (t_method)arp_octaves, gensym("octaves"),
		    A_DEFFLOAT, 0);
    class_addmethod(arp_class,
		    (t_method)arp_mode, gensym("mode"),
		    A_DEFFLOAT, 0);
}

# Makefile
# (c) 2006 IOhannes m zmölnig

# path to pd
## change this according to your setup!
#PDROOT=/home/atte/software/pd/current/


# here we find the sources of pd (and evtl. the pd.lib)
PDSRCDIR=$(PDROOT)/src
PDLIBDIR=$(PDROOT)/bin

# this is the filename-extension
# people have to specify it at the cmdline: eg "make pd_linux"
EXTENSION=$(MAKECMDGOALS)

# if no filename-extension is supplied by the user
# try to guess one, based on what "uname" tells us
UNAME := $(shell uname -s)
ifeq ($(UNAME),Linux)
  DEFAULTEXTENSION= pd_linux
else
  ifeq ($(UNAME),Darwin)
    DEFAULTEXTENSION= pd_darwin
  else
    ifeq (MINGW,$(findstring MINGW,$(UNAME)))
      DEFAULTEXTENSION= pd_nt
    else
      ifeq ($(UNAME),IRIX)
        UNAMEV := $(shell uname -R)
        ifeq (6.,$(findstring 6.,$(UNAMEV)))
          DEFAULTEXTENSION= pd_irix6
        else
          DEFAULTEXTENSION= pd_irix5
        endif
      else
        DEFAULTEXTENSION=help
      endif
    endif
  endif
endif

# if no extension is given, call "make" again with a guessed extension
auto:
        make $(DEFAULTEXTENSION)

# just a stupid fallback
help: 
        @echo "choose one command:  make pd_linux (linux), make pd_darwin 
(osX), make pd_irix5 (IRIX5), make pd_irix6 (IRIX6), make dll (MSVC), make 
pd_nt (MinWG)"

# delete old build files
clean:
        -rm -f *.dll *.pd_* *.o *.obj *~

# we want to compile all C-files we find in the current directory
SOURCES=$(sort $(filter %.c, $(wildcard *.c)))
# each C-files maps will become an external with the given filename-extension
TARGETS=$(SOURCES:.c=.$(EXTENSION))


# ----------------------- Linux -----------------------

pd_linux: $(TARGETS)

LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
    -Wall -W -Wshadow -Wstrict-prototypes -Werror \
    -Wno-unused -Wno-parentheses -Wno-switch

LINUXLDFLAGS =  -export_dynamic -shared  -lc -lm

LINUXINCLUDE =  -I$(PDSRCDIR)

%.pd_linux: %.c
        $(CC) $(LINUXLDFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.pd_linux $*.c
        strip --strip-unneeded $*.pd_linux



# ----------------------- Mac OSX -----------------------

pd_darwin: $(TARGETS)

DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
    -Wno-unused -Wno-parentheses -Wno-switch

DARWININCLUDE = -I$(PDSRCDIR)

DARWINLDFLAGS = -bundle -undefined suppress -flat_namespace

%.pd_darwin: %.c
        $(CC) $(DARWINCFLAGS) $(DARWININCLUDE) $(DARWINLDFLAGS) -o $*.pd_darwin 
$*.c


# ----------------------- IRIX 5.x -----------------------
pd_irix5: $(TARGETS)

SGICFLAGS5 = -o32 -DPD -DSGI -O2

SGIINCLUDE =  -I$(PDSRCDIR)

SGILDFLAGS =  -elf -shared -rdata_shared

%.pd_irix5: %.c
        $(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
        $(LD) $(SGILDFLAGS) -o $*.pd_irix5 $*.o
        rm $*.o


# ----------------------- IRIX 6.x -----------------------
pd_irix6: $(TARGETS)

SGICFLAGS6 = -DPD -DSGI -n32 \
        -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
        -Ofast=ip32

%.pd_irix6: %.c
        $(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
        $(LD) $(SGILDFLAGS) -o $*.pd_irix6 $*.o
        rm $*.o


# ----------------------- NT -----------------------
dll: $(TARGETS)

PDNTCFLAGS = /W3 /WX /DPD /DNT /D__WIN32__ /DMSW /nologo

VC="C:\Programme\Microsoft Visual Studio\Vc98"

PDNTINCLUDE = /I. /I$(PDROOT)\tcl\include /I$(PDSRCDIR)\src /I$(VC)\include

PDNTLDIR = $(VC)\lib

PDNTLIB = $(PDNTLDIR)\libc.lib \
        $(PDNTLDIR)\oldnames.lib \
        $(PDNTLDIR)\kernel32.lib \
        $(PDLIBDIR)\pd.lib 

%.dll: %.c
        cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
        link /dll /export:$*_setup $*.obj $(PDNTLIB)


pd_nt: $(TARGETS)

MINGWCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
    -Wall -W -Wshadow -Wstrict-prototypes -Werror \
    -Wno-unused -Wno-parentheses -Wno-switch -mms-bitfields

MINGWLDFLAGS =  -export_dynamic -shared -lm -lkernel32 -lcoldname -lcrtdll -lpd 
-L$(PDLIBDIR)

MINGWINCLUDE =  -I$(PDSRCDIR)

%.pd_nt: %.c
        $(CC) $(MINGWLDFLAGS) $(MINGWCFLAGS) $(MINGWINCLUDE) -o $*.dll $*.c
_______________________________________________
[email protected] mailing list
UNSUBSCRIBE and account-management -> 
http://lists.puredata.info/listinfo/pd-list

Reply via email to