forked from len0rd/rockbox
pdbox: Source cleanup. Removed unneeded files.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26497 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
5edd8cf736
commit
c1ae4414d4
44 changed files with 17 additions and 19949 deletions
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
Written by Matt Wright, The Center for New Music and Audio Technologies,
|
||||
University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
|
||||
The Regents of the University of California (Regents).
|
||||
|
||||
Permission to use, copy, modify, distribute, and distribute modified versions
|
||||
of this software and its documentation without fee and without a signed
|
||||
licensing agreement, is hereby granted, provided that the above copyright
|
||||
notice, this paragraph and the following two paragraphs appear in all copies,
|
||||
modifications, and distributions.
|
||||
|
||||
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
OSC-client.h: library for constructing OpenSoundControl messages.
|
||||
Derived from SynthControl.h
|
||||
Author: Matt Wright
|
||||
Version 0.1: 6/13/97
|
||||
Version 0.2: 7/21/2000: Support for type-tagged messages
|
||||
|
||||
|
||||
General notes:
|
||||
|
||||
This library abstracts away the data format for the OpenSoundControl
|
||||
protocol. Users of this library can construct OpenSoundControl packets
|
||||
with a function call interface instead of knowing how to lay out the bits.
|
||||
|
||||
All issues of memory allocation are deferred to the user of this library.
|
||||
There are two data structures that the user must allocate. The first
|
||||
is the actual buffer that the message will be written into. This buffer
|
||||
can be any size, but if it's too small there's a possibility that it
|
||||
will become overfull. The other data structure is called an OSCbuf,
|
||||
and it holds all the state used by the library as it's constructing
|
||||
a buffer.
|
||||
|
||||
All procedures that have the possibility of an error condition return int,
|
||||
with 0 indicating no error and nonzero indicating an error. The variable
|
||||
OSC_errorMessage will be set to point to a string containing an error
|
||||
message explaining what the problem is.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* The int4byte type has to be a 4-byte integer. You may have to
|
||||
change this to long or something else on your system. */
|
||||
#ifdef __MWERKS__
|
||||
/* In Metrowerks you can set ints to be 2 or 4 bytes on 68K, but long is
|
||||
always 4 bytes */
|
||||
typedef long int4byte;
|
||||
#else
|
||||
typedef int int4byte;
|
||||
#endif
|
||||
|
||||
/* OSC_timetag.h */
|
||||
|
||||
typedef struct {
|
||||
int seconds;
|
||||
int fraction;
|
||||
} OSCTimeTag;
|
||||
|
||||
OSCTimeTag OSCTT_Immediately(void);
|
||||
OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset);
|
||||
OSCTimeTag OSCTT_CurrentTime(void);
|
||||
|
||||
|
||||
|
||||
/* The maximum depth of bundles within bundles within bundles within...
|
||||
This is the size of a static array. If you exceed this limit you'll
|
||||
get an error message. */
|
||||
#define MAX_BUNDLE_NESTING 32
|
||||
|
||||
|
||||
/* Don't ever manipulate the data in the OSCbuf struct directly. (It's
|
||||
declared here in the header file only so your program will be able to
|
||||
declare variables of type OSCbuf and have the right amount of memory
|
||||
be allocated.) */
|
||||
|
||||
typedef struct OSCbuf_struct {
|
||||
char *buffer; /* The buffer to hold the OSC packet */
|
||||
int size; /* Size of the buffer */
|
||||
char *bufptr; /* Current position as we fill the buffer */
|
||||
int state; /* State of partially-constructed message */
|
||||
int4byte *thisMsgSize; /* Pointer to count field before
|
||||
currently-being-written message */
|
||||
int4byte *prevCounts[MAX_BUNDLE_NESTING];
|
||||
/* Pointers to count field before each currently
|
||||
open bundle */
|
||||
int bundleDepth; /* How many sub-sub-bundles are we in now? */
|
||||
char *typeStringPtr; /* This pointer advances through the type
|
||||
tag string as you add arguments. */
|
||||
int gettingFirstUntypedArg; /* nonzero if this message doesn't have
|
||||
a type tag and we're waiting for the 1st arg */
|
||||
} OSCbuf;
|
||||
|
||||
|
||||
|
||||
/* Initialize the given OSCbuf. The user of this module must pass in the
|
||||
block of memory that this OSCbuf will use for a buffer, and the number of
|
||||
bytes in that block. (It's the user's job to allocate the memory because
|
||||
you do it differently in different systems.) */
|
||||
void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray);
|
||||
|
||||
|
||||
/* Reset the given OSCbuf. Do this after you send out the contents of
|
||||
the buffer and want to start writing new data into it. */
|
||||
void OSC_resetBuffer(OSCbuf *buf);
|
||||
|
||||
|
||||
/* Is the buffer empty? (I.e., would it be stupid to send the buffer
|
||||
contents to the synth?) */
|
||||
int OSC_isBufferEmpty(OSCbuf *buf);
|
||||
|
||||
|
||||
/* How much space is left in the buffer? */
|
||||
int OSC_freeSpaceInBuffer(OSCbuf *buf);
|
||||
|
||||
/* Does the buffer contain a valid OSC packet? (Returns nonzero if yes.) */
|
||||
int OSC_isBufferDone(OSCbuf *buf);
|
||||
|
||||
/* When you're ready to send out the buffer (i.e., when OSC_isBufferDone()
|
||||
returns true), call these two procedures to get the OSC packet that's been
|
||||
assembled and its size in bytes. (And then call OSC_resetBuffer() if you
|
||||
want to re-use this OSCbuf for the next packet.) */
|
||||
char *OSC_getPacket(OSCbuf *buf);
|
||||
int OSC_packetSize(OSCbuf *buf);
|
||||
|
||||
|
||||
|
||||
/* Here's the basic model for building up OSC messages in an OSCbuf:
|
||||
|
||||
- Make sure the OSCbuf has been initialized with OSC_initBuffer().
|
||||
|
||||
- To open a bundle, call OSC_openBundle(). You can then write
|
||||
messages or open new bundles within the bundle you opened.
|
||||
Call OSC_closeBundle() to close the bundle. Note that a packet
|
||||
does not have to have a bundle; it can instead consist of just a
|
||||
single message.
|
||||
|
||||
|
||||
- For each message you want to send:
|
||||
|
||||
- Call OSC_writeAddress() with the name of your message. (In
|
||||
addition to writing your message name into the buffer, this
|
||||
procedure will also leave space for the size count of this message.)
|
||||
|
||||
- Alternately, call OSC_writeAddressAndTypes() with the name of
|
||||
your message and with a type string listing the types of all the
|
||||
arguments you will be putting in this message.
|
||||
|
||||
- Now write each of the arguments into the buffer, by calling one of:
|
||||
OSC_writeFloatArg()
|
||||
OSC_writeFloatArgs()
|
||||
OSC_writeIntArg()
|
||||
OSC_writeStringArg()
|
||||
|
||||
- Now your message is complete; you can send out the buffer or you can
|
||||
add another message to it.
|
||||
*/
|
||||
|
||||
int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
|
||||
int OSC_closeBundle(OSCbuf *buf);
|
||||
int OSC_closeAllBundles(OSCbuf *buf);
|
||||
|
||||
int OSC_writeAddress(OSCbuf *buf, char *name);
|
||||
int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types);
|
||||
int OSC_writeFloatArg(OSCbuf *buf, float arg);
|
||||
int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args);
|
||||
int OSC_writeIntArg(OSCbuf *buf, int4byte arg);
|
||||
int OSC_writeStringArg(OSCbuf *buf, char *arg);
|
||||
|
||||
extern char *OSC_errorMessage;
|
||||
|
||||
/* How many bytes will be needed in the OSC format to hold the given
|
||||
string? The length of the string, plus the null char, plus any padding
|
||||
needed for 4-byte alignment. */
|
||||
int OSC_effectiveStringLength(char *string);
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#N canvas 0 0 240 300 10;
|
||||
#X obj 32 185 dumpOSC 5550;
|
||||
#X obj 32 217 OSCroute /hello;
|
||||
#X obj 32 239 print;
|
||||
#X obj 133 238 print;
|
||||
#X obj 26 87 sendOSC;
|
||||
#X msg 50 43 connect localhost 5550;
|
||||
#X msg 21 13 send /hello PDa;
|
||||
#X connect 0 0 1 0;
|
||||
#X connect 1 0 2 0;
|
||||
#X connect 1 1 3 0;
|
||||
#X connect 5 0 4 0;
|
||||
#X connect 6 0 4 0;
|
||||
|
||||
|
|
@ -1,628 +0,0 @@
|
|||
/*
|
||||
Written by Adrian Freed, The Center for New Music and Audio Technologies,
|
||||
University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04
|
||||
The Regents of the University of California (Regents).
|
||||
|
||||
Permission to use, copy, modify, distribute, and distribute modified versions
|
||||
of this software and its documentation without fee and without a signed
|
||||
licensing agreement, is hereby granted, provided that the above copyright
|
||||
notice, this paragraph and the following two paragraphs appear in all copies,
|
||||
modifications, and distributions.
|
||||
|
||||
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
|
||||
The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
|
||||
*/
|
||||
|
||||
/* OSC-route.c
|
||||
Max object for OSC-style dispatching
|
||||
|
||||
To-do:
|
||||
|
||||
Match a pattern against a pattern?
|
||||
Declare outlet types / distinguish leaf nodes from other children
|
||||
More sophisticated (2-pass?) allmessages scheme
|
||||
set message?
|
||||
|
||||
|
||||
pd
|
||||
-------------
|
||||
-- tweaks for Win32 www.zeggz.com/raf 13-April-2002
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef ROCKBOX
|
||||
#include "plugin.h"
|
||||
#include "../../pdbox.h"
|
||||
#else /* ROCKBOX */
|
||||
#ifdef WIN32
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#endif /* ROCKBOX */
|
||||
|
||||
/* structure definition of your object */
|
||||
|
||||
#define MAX_NUM 20
|
||||
#define OSC_ROUTE_VERSION "1.05"
|
||||
#define OSCWarning(x...) post(x)
|
||||
|
||||
/* the required include files */
|
||||
#include "../src/m_pd.h"
|
||||
|
||||
|
||||
#ifndef TRUE
|
||||
typedef int Boolean;
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Fixed byte width types */
|
||||
typedef int int4; /* 4 byte int */
|
||||
|
||||
Boolean PatternMatch (const char *pattern, const char *test);
|
||||
|
||||
|
||||
|
||||
/* Version 1.04: Allows #1 thru #9 as typed-in arguments
|
||||
Version 1.05: Allows "list" messages as well as "message" messages.
|
||||
*/
|
||||
|
||||
static t_class *OSCroute_class;
|
||||
|
||||
typedef struct _OSCroute
|
||||
{
|
||||
t_object x_obj; // required header
|
||||
t_int x_num; // Number of address prefixes we store
|
||||
t_int x_complainmode; // Do we print a message if no match?
|
||||
t_int x_sendmode; // use pd internal sends instead of outlets
|
||||
char *x_prefixes[MAX_NUM];
|
||||
void *x_outlets[MAX_NUM+1];
|
||||
} t_OSCroute;
|
||||
|
||||
t_symbol *ps_list, *ps_complain, *ps_emptySymbol;
|
||||
|
||||
/* prototypes */
|
||||
|
||||
void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
||||
void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
||||
void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
||||
/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
|
||||
void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
|
||||
void OSCroute_version (t_OSCroute *x);
|
||||
/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */
|
||||
/* char *dstString); */
|
||||
void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
|
||||
|
||||
static char *NextSlashOrNull(char *p);
|
||||
static void StrCopyUntilSlash(char *target, const char *source);
|
||||
|
||||
|
||||
// free
|
||||
static void OSCroute_free(t_OSCroute *x)
|
||||
{
|
||||
#ifdef ROCKBOX
|
||||
(void) x;
|
||||
#endif
|
||||
// freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
|
||||
}
|
||||
|
||||
/* initialization routine */
|
||||
|
||||
// setup
|
||||
#ifdef WIN32
|
||||
OSC_API void OSCroute_setup(void) {
|
||||
#else
|
||||
void OSCroute_setup(void) {
|
||||
#endif
|
||||
OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
|
||||
(t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
|
||||
class_addlist(OSCroute_class, OSCroute_list);
|
||||
class_addanything(OSCroute_class, OSCroute_anything);
|
||||
class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
|
||||
class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));
|
||||
|
||||
/*
|
||||
class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
|
||||
gensym("connect"), A_SYMBOL, A_FLOAT, 0);
|
||||
class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
|
||||
gensym("disconnect"), 0);
|
||||
class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
|
||||
A_GIMME, 0);
|
||||
*/
|
||||
/* ps_list = gensym("list"); */
|
||||
/* ps_complain = gensym("complain"); */
|
||||
ps_emptySymbol = gensym("");
|
||||
|
||||
post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
|
||||
post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* instance creation routine */
|
||||
|
||||
void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
#ifdef ROCKBOX
|
||||
(void) s;
|
||||
#endif
|
||||
t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize
|
||||
|
||||
int i; //{{raf}} n not used
|
||||
|
||||
// EnterCallback();
|
||||
|
||||
if (argc > MAX_NUM) {
|
||||
post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
|
||||
// ExitCallback();
|
||||
return 0;
|
||||
}
|
||||
|
||||
x->x_complainmode = 0;
|
||||
x->x_num = 0;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (argv[i].a_type == A_SYMBOL) {
|
||||
if (argv[i].a_w.w_symbol->s_name[0] == '/') {
|
||||
/* Now that's a nice prefix */
|
||||
x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
|
||||
++(x->x_num);
|
||||
} else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
|
||||
argv[i].a_w.w_symbol->s_name[1] >= '1' &&
|
||||
argv[i].a_w.w_symbol->s_name[1] <= '9') {
|
||||
/* The Max programmer is trying to make a patch that will be
|
||||
a subpatch with arguments. We have to make an outlet for this
|
||||
argument. */
|
||||
x->x_prefixes[i] = "dummy";
|
||||
++(x->x_num);
|
||||
} else {
|
||||
/* Maybe this is an option we support */
|
||||
|
||||
/* if (argv[i].a_w.w_sym == ps_complain) { */
|
||||
/* x->x_complainmode = 1; */
|
||||
/* } else { */
|
||||
/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
|
||||
/* } */
|
||||
|
||||
}
|
||||
|
||||
// no LONG
|
||||
|
||||
/* } else if (argv[i].a_type == A_FLOAD) { */
|
||||
/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */
|
||||
/* char *string = getbytes(12); */
|
||||
/* // I can't be bothered to plug this 12 byte memory leak */
|
||||
/* if (string == 0) { */
|
||||
/* post("* OSC-route: out of memory!"); */
|
||||
/* // ExitCallback(); */
|
||||
/* return 0; */
|
||||
/* } */
|
||||
/* sprintf(string, "%d", argv[i].a_w.w_long); */
|
||||
/* x->x_prefixes[i] = string; */
|
||||
/* ++(x->x_num); */
|
||||
|
||||
} else if (argv[i].a_type == A_FLOAT) {
|
||||
post("* OSC-route: float arguments are not OK.");
|
||||
// ExitCallback();
|
||||
return 0;
|
||||
} else {
|
||||
post("* OSC-route: unrecognized argument type!");
|
||||
// ExitCallback();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Have to create the outlets in reverse order */
|
||||
/* well, not in pd ? */
|
||||
// for (i = x->x_num-1; i >= 0; --i) {
|
||||
// for (i = 0; i <= x->x_num-1; i++) {
|
||||
for (i = 0; i <= x->x_num; i++) {
|
||||
// x->x_outlets[i] = listout(x);
|
||||
x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
|
||||
}
|
||||
|
||||
// ExitCallback();
|
||||
return (x);
|
||||
}
|
||||
|
||||
|
||||
void OSCroute_version (t_OSCroute *x) {
|
||||
#ifdef ROCKBOX
|
||||
(void) x;
|
||||
#endif
|
||||
// EnterCallback();
|
||||
post("OSCroute Version " OSC_ROUTE_VERSION
|
||||
", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
|
||||
// ExitCallback();
|
||||
}
|
||||
|
||||
/* I don't know why these aren't defined in some Max #include file. */
|
||||
#define ASSIST_INLET 1
|
||||
#define ASSIST_OUTLET 2
|
||||
|
||||
void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg,
|
||||
char *dstString) {
|
||||
#ifdef ROCKBOX
|
||||
(void) box;
|
||||
#endif
|
||||
// EnterCallback();
|
||||
|
||||
if (msg==ASSIST_INLET) {
|
||||
#ifdef ROCKBOX
|
||||
strcpy(dstString, "Incoming OSC messages");
|
||||
#else
|
||||
sprintf(dstString, "Incoming OSC messages");
|
||||
#endif
|
||||
} else if (msg==ASSIST_OUTLET) {
|
||||
if (arg < 0 || arg >= x->x_num) {
|
||||
post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
|
||||
} else {
|
||||
#ifdef ROCKBOX
|
||||
strcpy(dstString, "subaddress + args for prefix ");
|
||||
strcat(dstString, x->x_prefixes[arg]);
|
||||
#else
|
||||
sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
post("* OSCroute_assist: unrecognized message %ld", msg);
|
||||
}
|
||||
|
||||
// ExitCallback();
|
||||
}
|
||||
|
||||
void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
||||
#ifdef ROCKBOX
|
||||
(void) s;
|
||||
#endif
|
||||
// EnterCallback();
|
||||
if (argc > 0 && argv[0].a_type == A_SYMBOL) {
|
||||
/* Ignore the fact that this is a "list" */
|
||||
OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
|
||||
} else {
|
||||
// post("* OSC-route: invalid list beginning with a number");
|
||||
// output on unmatched outlet jdl 20020908
|
||||
if (argv[0].a_type == A_FLOAT) {
|
||||
outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
|
||||
} else {
|
||||
post("* OSC-route: unrecognized atom type!");
|
||||
}
|
||||
}
|
||||
// ExitCallback();
|
||||
}
|
||||
|
||||
|
||||
void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
||||
// EnterCallback();
|
||||
OSCroute_doanything(x, s, argc, argv);
|
||||
// ExitCallback();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
||||
char *pattern, *nextSlash;
|
||||
int i;
|
||||
int matchedAnything;
|
||||
// post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
|
||||
|
||||
pattern = s->s_name;
|
||||
if (pattern[0] != '/') {
|
||||
post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
|
||||
outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
|
||||
return;
|
||||
}
|
||||
|
||||
matchedAnything = 0;
|
||||
|
||||
nextSlash = NextSlashOrNull(pattern+1);
|
||||
if (*nextSlash == '\0') {
|
||||
/* last level of the address, so we'll output the argument list */
|
||||
|
||||
|
||||
#ifdef NULL_IS_DIFFERENT_FROM_BANG
|
||||
if (argc==0) {
|
||||
post("* OSC-route: why are you matching one level pattern %s with no args?",
|
||||
pattern);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < x->x_num; ++i) {
|
||||
if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
|
||||
++matchedAnything;
|
||||
|
||||
// I hate stupid Max lists with a special first element
|
||||
if (argc == 0) {
|
||||
outlet_bang(x->x_outlets[i]);
|
||||
} else if (argv[0].a_type == A_SYMBOL) {
|
||||
// Promote the symbol that was argv[0] to the special symbol
|
||||
outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
|
||||
} else if (argc > 1) {
|
||||
// Multiple arguments starting with a number, so naturally we have
|
||||
// to use a special function to output this "list", since it's what
|
||||
// Max originally meant by "list".
|
||||
outlet_list(x->x_outlets[i], 0L, argc, argv);
|
||||
} else {
|
||||
// There was only one argument, and it was a number, so we output it
|
||||
// not as a list
|
||||
/* if (argv[0].a_type == A_LONG) { */
|
||||
|
||||
/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
|
||||
// } else
|
||||
if (argv[0].a_type == A_FLOAT) {
|
||||
|
||||
outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
|
||||
} else {
|
||||
post("* OSC-route: unrecognized atom type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* There's more address after this part, so our output list will begin with
|
||||
the next slash. */
|
||||
t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
|
||||
char patternBegin[1000];
|
||||
|
||||
|
||||
/* Get the first level of the incoming pattern to match against all our prefixes */
|
||||
StrCopyUntilSlash(patternBegin, pattern+1);
|
||||
|
||||
for (i = 0; i < x->x_num; ++i) {
|
||||
if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
|
||||
++matchedAnything;
|
||||
if (restOfPattern == 0) {
|
||||
restOfPattern = gensym(nextSlash);
|
||||
}
|
||||
outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x->x_complainmode) {
|
||||
if (!matchedAnything) {
|
||||
post("* OSC-route: pattern %s did not match any prefixes", pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
|
||||
if (!matchedAnything) {
|
||||
outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static char *NextSlashOrNull(char *p) {
|
||||
while (*p != '/' && *p != '\0') {
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void StrCopyUntilSlash(char *target, const char *source) {
|
||||
while (*source != '/' && *source != '\0') {
|
||||
*target = *source;
|
||||
++target;
|
||||
++source;
|
||||
}
|
||||
*target = 0;
|
||||
}
|
||||
|
||||
static int MyStrCopy(char *target, const char *source) {
|
||||
int i = 0;
|
||||
while (*source != '\0') {
|
||||
*target = *source;
|
||||
++target;
|
||||
++source;
|
||||
++i;
|
||||
}
|
||||
*target = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
|
||||
int i;
|
||||
t_symbol *prefixSymbol = 0;
|
||||
char prefixBuf[1000];
|
||||
char *endOfPrefix;
|
||||
t_atom a[1];
|
||||
|
||||
if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
|
||||
prefixSymbol = argv[0].a_w.w_symbol;
|
||||
endOfPrefix = prefixBuf + MyStrCopy(prefixBuf,
|
||||
prefixSymbol->s_name);
|
||||
} else {
|
||||
prefixSymbol = ps_emptySymbol;
|
||||
prefixBuf[0] = '\0';
|
||||
endOfPrefix = prefixBuf;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < x->x_num; ++i) {
|
||||
post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
|
||||
MyStrCopy(endOfPrefix, x->x_prefixes[i]);
|
||||
SETSYMBOL(a, gensym(prefixBuf));
|
||||
outlet_anything(x->x_outlets[i], s, 1, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
static const char *theWholePattern; /* Just for warning messages */
|
||||
|
||||
static Boolean MatchBrackets (const char *pattern, const char *test);
|
||||
static Boolean MatchList (const char *pattern, const char *test);
|
||||
|
||||
Boolean PatternMatch (const char * pattern, const char * test) {
|
||||
theWholePattern = pattern;
|
||||
|
||||
if (pattern == 0 || pattern[0] == 0) {
|
||||
return test[0] == 0;
|
||||
}
|
||||
|
||||
if (test[0] == 0) {
|
||||
if (pattern[0] == '*')
|
||||
return PatternMatch (pattern+1,test);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (pattern[0]) {
|
||||
case 0 : return test[0] == 0;
|
||||
case '?' : return PatternMatch (pattern + 1, test + 1);
|
||||
case '*' :
|
||||
if (PatternMatch (pattern+1, test)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return PatternMatch (pattern, test+1);
|
||||
}
|
||||
case ']' :
|
||||
case '}' :
|
||||
OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
|
||||
return FALSE;
|
||||
case '[' :
|
||||
return MatchBrackets (pattern,test);
|
||||
case '{' :
|
||||
return MatchList (pattern,test);
|
||||
case '\\' :
|
||||
if (pattern[1] == 0) {
|
||||
return test[0] == 0;
|
||||
} else if (pattern[1] == test[0]) {
|
||||
return PatternMatch (pattern+2,test+1);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
default :
|
||||
if (pattern[0] == test[0]) {
|
||||
return PatternMatch (pattern+1,test+1);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* we know that pattern[0] == '[' and test[0] != 0 */
|
||||
|
||||
static Boolean MatchBrackets (const char *pattern, const char *test) {
|
||||
Boolean result;
|
||||
Boolean negated = FALSE;
|
||||
const char *p = pattern;
|
||||
|
||||
if (pattern[1] == 0) {
|
||||
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pattern[1] == '!') {
|
||||
negated = TRUE;
|
||||
p++;
|
||||
}
|
||||
|
||||
while (*p != ']') {
|
||||
if (*p == 0) {
|
||||
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
||||
return FALSE;
|
||||
}
|
||||
if (p[1] == '-' && p[2] != 0) {
|
||||
if (test[0] >= p[0] && test[0] <= p[2]) {
|
||||
result = !negated;
|
||||
goto advance;
|
||||
}
|
||||
}
|
||||
if (p[0] == test[0]) {
|
||||
result = !negated;
|
||||
goto advance;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
result = negated;
|
||||
|
||||
advance:
|
||||
|
||||
if (!result)
|
||||
return FALSE;
|
||||
|
||||
while (*p != ']') {
|
||||
if (*p == 0) {
|
||||
OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
|
||||
return FALSE;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return PatternMatch (p+1,test+1);
|
||||
}
|
||||
|
||||
static Boolean MatchList (const char *pattern, const char *test) {
|
||||
|
||||
const char *restOfPattern, *tp = test;
|
||||
|
||||
|
||||
for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
|
||||
if (*restOfPattern == 0) {
|
||||
OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
restOfPattern++; /* skip close curly brace */
|
||||
|
||||
|
||||
pattern++; /* skip open curly brace */
|
||||
|
||||
while (1) {
|
||||
|
||||
if (*pattern == ',') {
|
||||
if (PatternMatch (restOfPattern, tp)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
tp = test;
|
||||
++pattern;
|
||||
}
|
||||
} else if (*pattern == '}') {
|
||||
return PatternMatch (restOfPattern, tp);
|
||||
} else if (*pattern == *tp) {
|
||||
++pattern;
|
||||
++tp;
|
||||
} else {
|
||||
tp = test;
|
||||
while (*pattern != ',' && *pattern != '}') {
|
||||
pattern++;
|
||||
}
|
||||
if (*pattern == ',') {
|
||||
pattern++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#N canvas 428 285 240 300 8;
|
||||
#X obj 24 78 noise~;
|
||||
#X obj 15 215 dac~;
|
||||
#X obj 24 167 biquad~;
|
||||
#X floatatom 67 76 5 0 0 0 - - -;
|
||||
#X floatatom 83 111 5 0 0 0 - - -;
|
||||
#X obj 67 138 bandpass 600 10;
|
||||
#X text 77 97 bandwidth: 100 = 1 octave;
|
||||
#X text 67 58 frequency;
|
||||
#X text 8 11 Calculation of biquad coefficients;
|
||||
#X text 7 21 ==================================;
|
||||
#X connect 0 0 2 0;
|
||||
#X connect 2 0 1 0;
|
||||
#X connect 2 0 1 1;
|
||||
#X connect 3 0 5 0;
|
||||
#X connect 4 0 5 1;
|
||||
#X connect 5 0 2 0;
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,486 +0,0 @@
|
|||
/* ------------------------ fatom ----------------------------- */
|
||||
|
||||
#define x_val a_pos.a_w.w_float
|
||||
#define DEBUG(x)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct _fatom
|
||||
{
|
||||
t_object x_obj;
|
||||
t_atom a_pos; /* the value of the fatom */
|
||||
|
||||
t_symbol* x_send;
|
||||
t_symbol* x_receive;
|
||||
t_glist * x_glist; /* value of the current canvas, intialized in _new */
|
||||
int x_rect_width; /* width of the widget */
|
||||
int x_rect_height; /* height of the widget */
|
||||
t_symbol* x_sym; /* symbol for receiving callbacks from GUI */
|
||||
t_symbol* x_type; /* type of fatom (vslider, hslider, checkbutton) */
|
||||
|
||||
t_symbol* x_text; /* associated widget text */
|
||||
int x_max; /* maximum value of a_pos (x_val) */
|
||||
int x_min; /* minimum value of a_pos (x_val) */
|
||||
int x_width; /* width of widget (e.g x_rect_height + 15 for hslider, x_rect_width + 15 for slider) */
|
||||
t_symbol* x_color;
|
||||
t_symbol* x_bgcolor;
|
||||
} t_fatom;
|
||||
|
||||
/* widget helper functions */
|
||||
|
||||
|
||||
|
||||
|
||||
static void draw_inlets(t_fatom *x, t_glist *glist, int firsttime, int nin, int nout)
|
||||
{
|
||||
int n = nin;
|
||||
int nplus, i;
|
||||
nplus = (n == 1 ? 1 : n-1);
|
||||
DEBUG(post("draw inlet");)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
|
||||
if (firsttime)
|
||||
sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
|
||||
glist_getcanvas(glist),
|
||||
onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height,
|
||||
x, i);
|
||||
else
|
||||
sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
|
||||
glist_getcanvas(glist), x, i,
|
||||
onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 1,
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height);
|
||||
}
|
||||
n = nout;
|
||||
nplus = (n == 1 ? 1 : n-1);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH) * i / nplus;
|
||||
if (firsttime)
|
||||
sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
|
||||
glist_getcanvas(glist),
|
||||
onset, text_ypix(&x->x_obj, glist),
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1,
|
||||
x, i);
|
||||
else
|
||||
sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
|
||||
glist_getcanvas(glist), x, i,
|
||||
onset, text_ypix(&x->x_obj, glist),
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + 1);
|
||||
|
||||
}
|
||||
DEBUG(post("draw inlet end");)
|
||||
}
|
||||
|
||||
|
||||
static void draw_handle(t_fatom *x, t_glist *glist, int firsttime) {
|
||||
int onset = text_xpix(&x->x_obj, glist) + (x->x_rect_width - IOWIDTH+2);
|
||||
|
||||
if (firsttime)
|
||||
sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xhandle\n",
|
||||
glist_getcanvas(glist),
|
||||
onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4,
|
||||
x);
|
||||
else
|
||||
sys_vgui(".x%x.c coords %xhandle %d %d %d %d\n",
|
||||
glist_getcanvas(glist), x,
|
||||
onset, text_ypix(&x->x_obj, glist) + x->x_rect_height - 12,
|
||||
onset + IOWIDTH, text_ypix(&x->x_obj, glist) + x->x_rect_height-4);
|
||||
}
|
||||
|
||||
static void create_widget(t_fatom *x, t_glist *glist)
|
||||
{
|
||||
t_canvas *canvas=glist_getcanvas(glist);
|
||||
|
||||
if (!strcmp(x->x_type->s_name,"vslider")) {
|
||||
x->x_rect_width = x->x_width+15;
|
||||
x->x_rect_height = x->x_max-x->x_min+26;
|
||||
|
||||
sys_vgui("scale .x%x.c.s%x \
|
||||
-sliderlength 10 \
|
||||
-showvalue 0 \
|
||||
-length %d \
|
||||
-resolution 0.01 \
|
||||
-repeatinterval 20 \
|
||||
-from %d -to %d \
|
||||
-width %d \
|
||||
-bg %s \
|
||||
-activebackground %s \
|
||||
-troughcolor %s \
|
||||
-command fatom_cb%x\n",canvas,x,
|
||||
x->x_max-x->x_min+14,
|
||||
x->x_max,
|
||||
x->x_min,
|
||||
x->x_width,
|
||||
x->x_color->s_name,
|
||||
x->x_color->s_name,
|
||||
x->x_bgcolor->s_name,
|
||||
x);
|
||||
} else if (!strcmp(x->x_type->s_name,"hslider")) {
|
||||
x->x_rect_width = x->x_max-x->x_min + 24;
|
||||
x->x_rect_height = x->x_width + 15;
|
||||
sys_vgui("scale .x%x.c.s%x \
|
||||
-sliderlength 10 \
|
||||
-showvalue 0 \
|
||||
-length %d \
|
||||
-resolution 0.01 \
|
||||
-orient horizontal \
|
||||
-repeatinterval 20 \
|
||||
-from %d -to %d \
|
||||
-width %d \
|
||||
-bg %s \
|
||||
-activebackground %s \
|
||||
-troughcolor %s \
|
||||
-command fatom_cb%x\n",canvas,x,
|
||||
x->x_max-x->x_min+14,
|
||||
x->x_min,
|
||||
x->x_max,
|
||||
x->x_width,
|
||||
x->x_color->s_name,
|
||||
x->x_color->s_name,
|
||||
x->x_bgcolor->s_name,
|
||||
x);
|
||||
} else if (!strcmp(x->x_type->s_name,"checkbutton")) {
|
||||
x->x_rect_width = 32;
|
||||
x->x_rect_height = 28;
|
||||
sys_vgui("checkbutton .x%x.c.s%x \
|
||||
-command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -text \"%s\" \
|
||||
-bg %s \
|
||||
-activebackground %s \
|
||||
\n",canvas,x,x,x,x,
|
||||
x->x_text->s_name,
|
||||
x->x_color->s_name,
|
||||
x->x_bgcolor->s_name);
|
||||
} else if (!strcmp(x->x_type->s_name,"hradio")) {
|
||||
int i;
|
||||
x->x_rect_width = 8*20;
|
||||
x->x_rect_height = 25;
|
||||
for (i=0;i<8;i++) {
|
||||
sys_vgui("radiobutton .x%x.c.s%x%d \
|
||||
-command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
|
||||
}
|
||||
/* TODO pack them */
|
||||
} else if (!strcmp(x->x_type->s_name,"vradio")) {
|
||||
int i;
|
||||
x->x_rect_width = 30;
|
||||
x->x_rect_height = 20*8+5;
|
||||
for (i=0;i<8;i++) {
|
||||
sys_vgui("radiobutton .x%x.c.s%x%d \
|
||||
-command { fatom_cb%x $fatom_val%x} -variable fatom_val%x -value %d\n",canvas,x,i,x,x,x,i);
|
||||
}
|
||||
/* TODO pack them */
|
||||
} else {
|
||||
x->x_rect_width = 32;
|
||||
x->x_rect_height = 140;
|
||||
sys_vgui("scale .x%x.c.s%x \
|
||||
-sliderlength 10 \
|
||||
-showvalue 0 \
|
||||
-length 131 \
|
||||
-from 127 -to 0 \
|
||||
-command fatom_cb%x\n",canvas,x,x);
|
||||
}
|
||||
|
||||
/* set the start value */
|
||||
if (!strcmp(x->x_type->s_name,"checkbutton")) {
|
||||
if (x->x_val)
|
||||
sys_vgui(".x%x.c.s%x select\n",canvas,x,x->x_val);
|
||||
else
|
||||
sys_vgui(".x%x.c.s%x deselect\n",canvas,x,x->x_val);
|
||||
} else
|
||||
sys_vgui(".x%x.c.s%x set %f\n",canvas,x,x->x_val);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void fatom_drawme(t_fatom *x, t_glist *glist, int firsttime)
|
||||
{
|
||||
t_canvas *canvas=glist_getcanvas(glist);// x->x_glist;//glist_getcanvas(glist);
|
||||
DEBUG(post("drawme %d",firsttime);)
|
||||
if (firsttime) {
|
||||
DEBUG(post("glist %x canvas %x",x->x_glist,canvas));
|
||||
create_widget(x,glist);
|
||||
x->x_glist = canvas;
|
||||
sys_vgui(".x%x.c create window %d %d -anchor nw -window .x%x.c.s%x -tags %xS\n",
|
||||
canvas,text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2,x->x_glist,x,x);
|
||||
|
||||
}
|
||||
else {
|
||||
sys_vgui(".x%x.c coords %xS \
|
||||
%d %d\n",
|
||||
canvas, x,
|
||||
text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist)+2);
|
||||
}
|
||||
draw_inlets(x, glist, firsttime, 1,1);
|
||||
// draw_handle(x, glist, firsttime);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void fatom_erase(t_fatom* x,t_glist* glist)
|
||||
{
|
||||
int n;
|
||||
|
||||
DEBUG(post("erase");)
|
||||
sys_vgui("destroy .x%x.c.s%x\n",glist_getcanvas(glist),x);
|
||||
|
||||
sys_vgui(".x%x.c delete %xS\n",glist_getcanvas(glist), x);
|
||||
|
||||
/* inlets and outlets */
|
||||
|
||||
sys_vgui(".x%x.c delete %xi%d\n",glist_getcanvas(glist),x,0);
|
||||
sys_vgui(".x%x.c delete %xo%d\n",glist_getcanvas(glist),x,0);
|
||||
sys_vgui(".x%x.c delete %xhandle\n",glist_getcanvas(glist),x,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------ fatom widgetbehaviour----------------------------- */
|
||||
|
||||
|
||||
static void fatom_getrect(t_gobj *z, t_glist *owner,
|
||||
int *xp1, int *yp1, int *xp2, int *yp2)
|
||||
{
|
||||
int width, height;
|
||||
t_fatom* s = (t_fatom*)z;
|
||||
|
||||
width = s->x_rect_width;
|
||||
height = s->x_rect_height;
|
||||
*xp1 = text_xpix(&s->x_obj, owner);
|
||||
*yp1 = text_ypix(&s->x_obj, owner);
|
||||
*xp2 = text_xpix(&s->x_obj, owner) + width;
|
||||
*yp2 = text_ypix(&s->x_obj, owner) + height;
|
||||
}
|
||||
|
||||
static void fatom_displace(t_gobj *z, t_glist *glist,
|
||||
int dx, int dy)
|
||||
{
|
||||
t_fatom *x = (t_fatom *)z;
|
||||
DEBUG(post("displace");)
|
||||
x->x_obj.te_xpix += dx;
|
||||
x->x_obj.te_ypix += dy;
|
||||
if (glist_isvisible(glist))
|
||||
{
|
||||
sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
|
||||
glist_getcanvas(glist), x,
|
||||
text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
|
||||
text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height);
|
||||
|
||||
fatom_drawme(x, glist, 0);
|
||||
canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
|
||||
}
|
||||
DEBUG(post("displace end");)
|
||||
}
|
||||
|
||||
static void fatom_select(t_gobj *z, t_glist *glist, int state)
|
||||
{
|
||||
t_fatom *x = (t_fatom *)z;
|
||||
if (state) {
|
||||
sys_vgui(".x%x.c create rectangle \
|
||||
%d %d %d %d -tags %xSEL -outline blue\n",
|
||||
glist_getcanvas(glist),
|
||||
text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
|
||||
text_xpix(&x->x_obj, glist) + x->x_rect_width, text_ypix(&x->x_obj, glist) + x->x_rect_height,
|
||||
x);
|
||||
}
|
||||
else {
|
||||
sys_vgui(".x%x.c delete %xSEL\n",
|
||||
glist_getcanvas(glist), x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void fatom_activate(t_gobj *z, t_glist *glist, int state)
|
||||
{
|
||||
/* t_text *x = (t_text *)z;
|
||||
t_rtext *y = glist_findrtext(glist, x);
|
||||
if (z->g_pd != gatom_class) rtext_activate(y, state);*/
|
||||
}
|
||||
|
||||
static void fatom_delete(t_gobj *z, t_glist *glist)
|
||||
{
|
||||
t_text *x = (t_text *)z;
|
||||
canvas_deletelinesfor(glist_getcanvas(glist), x);
|
||||
}
|
||||
|
||||
|
||||
static void fatom_vis(t_gobj *z, t_glist *glist, int vis)
|
||||
{
|
||||
t_fatom* s = (t_fatom*)z;
|
||||
t_rtext *y;
|
||||
DEBUG(post("vis: %d",vis);)
|
||||
if (vis) {
|
||||
#ifdef PD_MINOR_VERSION
|
||||
y = (t_rtext *) rtext_new(glist, (t_text *)z);
|
||||
#else
|
||||
y = (t_rtext *) rtext_new(glist, (t_text *)z,0,0);
|
||||
#endif
|
||||
fatom_drawme(s, glist, 1);
|
||||
}
|
||||
else {
|
||||
y = glist_findrtext(glist, (t_text *)z);
|
||||
fatom_erase(s,glist);
|
||||
rtext_free(y);
|
||||
}
|
||||
}
|
||||
|
||||
static void fatom_save(t_gobj *z, t_binbuf *b);
|
||||
|
||||
t_widgetbehavior fatom_widgetbehavior;
|
||||
|
||||
|
||||
|
||||
|
||||
static void fatom_size(t_fatom* x,t_floatarg w,t_floatarg h) {
|
||||
x->x_rect_width = w;
|
||||
x->x_rect_height = h;
|
||||
}
|
||||
|
||||
static void fatom_color(t_fatom* x,t_symbol* col)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void fatom_f(t_fatom* x,t_floatarg f)
|
||||
{
|
||||
x->x_val = f;
|
||||
if (x->x_send == &s_)
|
||||
outlet_float(x->x_obj.ob_outlet,f);
|
||||
else
|
||||
if (x->x_send->s_thing) pd_float(x->x_send->s_thing,f);
|
||||
}
|
||||
|
||||
|
||||
static void fatom_float(t_fatom* x,t_floatarg f)
|
||||
{
|
||||
if (glist_isvisible(x->x_glist)) {
|
||||
if (!strcmp(x->x_type->s_name,"checkbutton")) {
|
||||
if (x->x_val)
|
||||
sys_vgui(".x%x.c.s%x select\n",x->x_glist,x,f);
|
||||
else
|
||||
sys_vgui(".x%x.c.s%x deselect\n",x->x_glist,x,f);
|
||||
} else
|
||||
sys_vgui(".x%x.c.s%x set %f\n",x->x_glist,x,f);
|
||||
}
|
||||
fatom_f(x,f);
|
||||
}
|
||||
|
||||
|
||||
static void fatom_bang(t_fatom* x,t_floatarg f)
|
||||
{
|
||||
outlet_float(x->x_obj.ob_outlet,x->x_val);
|
||||
}
|
||||
|
||||
|
||||
static void fatom_properties(t_gobj *z, t_glist *owner)
|
||||
{
|
||||
post("N/I");
|
||||
}
|
||||
|
||||
|
||||
static void fatom_save(t_gobj *z, t_binbuf *b)
|
||||
{
|
||||
|
||||
t_fatom *x = (t_fatom *)z;
|
||||
|
||||
binbuf_addv(b, "ssiiss", gensym("#X"),gensym("obj"),
|
||||
x->x_obj.te_xpix, x->x_obj.te_ypix ,
|
||||
gensym("fatom"),x->x_type);
|
||||
binbuf_addv(b, ";");
|
||||
}
|
||||
|
||||
|
||||
static void *fatom_new(t_fatom* x,int argc,t_atom* argv)
|
||||
{
|
||||
char buf[256];
|
||||
int n = 0;
|
||||
x->x_glist = canvas_getcurrent();
|
||||
|
||||
x->x_text = gensym("");
|
||||
x->x_max = 127;
|
||||
x->x_min = 0;
|
||||
x->x_width = 15;
|
||||
x->x_color = gensym("grey");
|
||||
x->x_bgcolor = gensym("grey");
|
||||
x->x_send = &s_;
|
||||
|
||||
while (argc) {
|
||||
if (argv->a_type == A_FLOAT) {
|
||||
if (n==0) x->x_max = atom_getfloat(argv);
|
||||
if (n==1) x->x_min = atom_getfloat(argv);
|
||||
if (n==2) x->x_width = atom_getfloat(argv);
|
||||
}
|
||||
|
||||
if (argv->a_type == A_SYMBOL) {
|
||||
post("%d: symbol value %s",n,atom_getsymbol(argv)->s_name);
|
||||
if (n==3) x->x_send = atom_getsymbol(argv);
|
||||
if (n==4) x->x_color = atom_getsymbol(argv);
|
||||
if (n==5) x->x_bgcolor = atom_getsymbol(argv);
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
n++;
|
||||
}
|
||||
|
||||
/* bind to a symbol for slider callback (later make this based on the
|
||||
filepath ??) */
|
||||
|
||||
sprintf(buf,"fatom%x",(t_int)x);
|
||||
x->x_sym = gensym(buf);
|
||||
pd_bind(&x->x_obj.ob_pd, x->x_sym);
|
||||
|
||||
/* pipe startup code to tk */
|
||||
|
||||
sys_vgui("proc fatom_cb%x {v} {\n pd [concat fatom%x f $v \\;]\n }\n",x,x);
|
||||
|
||||
outlet_new(&x->x_obj, &s_float);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void fatom_setup_common(t_class* class)
|
||||
{
|
||||
|
||||
fatom_widgetbehavior.w_getrectfn = fatom_getrect;
|
||||
fatom_widgetbehavior.w_displacefn = fatom_displace;
|
||||
fatom_widgetbehavior.w_selectfn = fatom_select;
|
||||
fatom_widgetbehavior.w_activatefn = fatom_activate;
|
||||
fatom_widgetbehavior.w_deletefn = fatom_delete;
|
||||
fatom_widgetbehavior.w_visfn = fatom_vis;
|
||||
#if PD_MINOR_VERSION < 37
|
||||
fatom_widgetbehavior.w_savefn = fatom_save;
|
||||
fatom_widgetbehavior.w_propertiesfn = NULL;
|
||||
#endif
|
||||
fatom_widgetbehavior.w_clickfn = NULL;
|
||||
|
||||
class_addfloat(class, (t_method)fatom_float);
|
||||
class_addbang(class, (t_method)fatom_bang);
|
||||
class_addmethod(class, (t_method)fatom_f, gensym("f"),
|
||||
A_FLOAT, 0);
|
||||
|
||||
/*
|
||||
class_addmethod(class, (t_method)fatom_size, gensym("size"),
|
||||
A_FLOAT, A_FLOAT, 0);
|
||||
|
||||
class_addmethod(class, (t_method)fatom_color, gensym("color"),
|
||||
A_SYMBOL, 0);
|
||||
*/
|
||||
/*
|
||||
class_addmethod(class, (t_method)fatom_open, gensym("open"),
|
||||
A_SYMBOL, 0);
|
||||
*/
|
||||
|
||||
class_setwidget(class,&fatom_widgetbehavior);
|
||||
#if PD_MINOR_VERSION >= 37
|
||||
class_setsavefn(class,&fatom_save);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#N canvas 0 0 240 300 8;
|
||||
#X obj 21 61 gcanvas 80 80;
|
||||
#X text 14 9 gcanvas .. mouse coordinate enabled canvas;
|
||||
#X text 13 22 ==========================================;
|
||||
#X floatatom 21 148 5 0 0 0 - - -;
|
||||
#X floatatom 94 147 5 0 0 0 - - -;
|
||||
#X connect 0 0 3 0;
|
||||
#X connect 0 1 4 0;
|
||||
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
VERSION = 0.2
|
||||
SOURCE = $(shell ls *.c)
|
||||
TARGETS = $(SOURCE:.c=.pd_linux)
|
||||
|
||||
EXT= pd_linux
|
||||
|
||||
AFLAGS = -g -O2 -I./ -DFIXEDPOINT
|
||||
EFLAGS = -shared -Wl,-export-dynamic
|
||||
PREFIX = /usr
|
||||
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
clean:
|
||||
-rm $(TARGETS)
|
||||
-rm *.o *~
|
||||
|
||||
tar: clean
|
||||
cd ..;tar czvf PDa-externals-$(VERSION).tgz PDa-externals
|
||||
|
||||
upload: tar
|
||||
scp ../PDa-externals-$(VERSION).tgz gige@xdv.org:~/www/pda/release
|
||||
|
||||
install:
|
||||
install -d $(DESTDIR)/$(PREFIX)/lib/pd/extra
|
||||
cp $(TARGETS) $(DESTDIR)/$(PREFIX)/lib/pd/extra
|
||||
|
||||
%.$(EXT) : %.o
|
||||
$(CC) -o $@ $(EFLAGS) $+
|
||||
|
||||
%.o : %.c
|
||||
$(CC) -c $(AFLAGS) $(CFLAGS) $+
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,56 +0,0 @@
|
|||
|
||||
#ifndef SFORMAT_H__
|
||||
#define SFORMAT_H__
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned long uint32;
|
||||
|
||||
#define FORMAT_WAVE 0
|
||||
#define FORMAT_AIFF 1
|
||||
#define FORMAT_NEXT 2
|
||||
|
||||
/* the NeXTStep sound header structure; can be big or little endian */
|
||||
|
||||
typedef struct _nextstep
|
||||
{
|
||||
char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
|
||||
uint32 ns_onset; /* byte offset of first sample */
|
||||
uint32 ns_length; /* length of sound in bytes */
|
||||
uint32 ns_format; /* format; see below */
|
||||
uint32 ns_sr; /* sample rate */
|
||||
uint32 ns_nchans; /* number of channels */
|
||||
char ns_info[4]; /* comment */
|
||||
} t_nextstep;
|
||||
|
||||
#define NS_FORMAT_LINEAR_16 3
|
||||
#define NS_FORMAT_LINEAR_24 4
|
||||
#define NS_FORMAT_FLOAT 6
|
||||
#define SCALE (1./(1024. * 1024. * 1024. * 2.))
|
||||
|
||||
/* the WAVE header. All Wave files are little endian. We assume
|
||||
the "fmt" chunk comes first which is usually the case but perhaps not
|
||||
always; same for AIFF and the "COMM" chunk. */
|
||||
|
||||
typedef unsigned word;
|
||||
typedef unsigned long dword;
|
||||
|
||||
typedef struct _wave
|
||||
{
|
||||
char w_fileid[4]; /* chunk id 'RIFF' */
|
||||
uint32 w_chunksize; /* chunk size */
|
||||
char w_waveid[4]; /* wave chunk id 'WAVE' */
|
||||
char w_fmtid[4]; /* format chunk id 'fmt ' */
|
||||
uint32 w_fmtchunksize; /* format chunk size */
|
||||
uint16 w_fmttag; /* format tag, 1 for PCM */
|
||||
uint16 w_nchannels; /* number of channels */
|
||||
uint32 w_samplespersec; /* sample rate in hz */
|
||||
uint32 w_navgbytespersec; /* average bytes per second */
|
||||
uint16 w_nblockalign; /* number of bytes per sample */
|
||||
uint16 w_nbitspersample; /* number of bits in a sample */
|
||||
char w_datachunkid[4]; /* data chunk id 'data' */
|
||||
uint32 w_datachunksize; /* length of data chunk */
|
||||
} t_wave;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
/* (C) Guenter Geiger <geiger@epy.co.at> */
|
||||
|
||||
#include "../src/m_pd.h"
|
||||
#ifdef NT
|
||||
#pragma warning( disable : 4244 )
|
||||
#pragma warning( disable : 4305 )
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
|
||||
void sys_rmpollfn(int fd);
|
||||
void sys_addpollfn(int fd, void* fn, void *ptr);
|
||||
|
||||
/* ------------------------ shell ----------------------------- */
|
||||
|
||||
#define INBUFSIZE 1024
|
||||
|
||||
static t_class *shell_class;
|
||||
|
||||
|
||||
static void drop_priority(void)
|
||||
{
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
struct sched_param par;
|
||||
int p1 ,p2, p3;
|
||||
par.sched_priority = 0;
|
||||
sched_setscheduler(0,SCHED_OTHER,&par);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
typedef struct _shell
|
||||
{
|
||||
t_object x_obj;
|
||||
int x_echo;
|
||||
char *sr_inbuf;
|
||||
int sr_inhead;
|
||||
int sr_intail;
|
||||
void* x_binbuf;
|
||||
int fdpipe[2];
|
||||
int fdinpipe[2];
|
||||
int pid;
|
||||
int x_del;
|
||||
t_outlet* x_done;
|
||||
t_clock* x_clock;
|
||||
} t_shell;
|
||||
|
||||
static int shell_pid;
|
||||
|
||||
|
||||
void shell_cleanup(t_shell* x)
|
||||
{
|
||||
sys_rmpollfn(x->fdpipe[0]);
|
||||
|
||||
if (x->fdpipe[0]>0) close(x->fdpipe[0]);
|
||||
if (x->fdpipe[1]>0) close(x->fdpipe[1]);
|
||||
if (x->fdinpipe[0]>0) close(x->fdinpipe[0]);
|
||||
if (x->fdinpipe[1]>0) close(x->fdinpipe[1]);
|
||||
|
||||
x->fdpipe[0] = -1;
|
||||
x->fdpipe[1] = -1;
|
||||
x->fdinpipe[0] = -1;
|
||||
x->fdinpipe[1] = -1;
|
||||
clock_unset(x->x_clock);
|
||||
}
|
||||
|
||||
void shell_check(t_shell* x)
|
||||
{
|
||||
int ret;
|
||||
int status;
|
||||
ret = waitpid(x->pid,&status,WNOHANG);
|
||||
if (ret == x->pid) {
|
||||
shell_cleanup(x);
|
||||
if (WIFEXITED(status)) {
|
||||
outlet_float(x->x_done,WEXITSTATUS(status));
|
||||
}
|
||||
else outlet_float(x->x_done,0);
|
||||
}
|
||||
else {
|
||||
if (x->x_del < 100) x->x_del+=2; /* increment poll times */
|
||||
clock_delay(x->x_clock,x->x_del);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void shell_bang(t_shell *x)
|
||||
{
|
||||
post("bang");
|
||||
}
|
||||
|
||||
/* snippet from pd's code */
|
||||
static void shell_doit(void *z, t_binbuf *b)
|
||||
{
|
||||
t_shell *x = (t_shell *)z;
|
||||
int msg, natom = binbuf_getnatom(b);
|
||||
t_atom *at = binbuf_getvec(b);
|
||||
|
||||
for (msg = 0; msg < natom;)
|
||||
{
|
||||
int emsg;
|
||||
for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
|
||||
&& at[emsg].a_type != A_SEMI; emsg++)
|
||||
;
|
||||
if (emsg > msg)
|
||||
{
|
||||
int i;
|
||||
for (i = msg; i < emsg; i++)
|
||||
if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
|
||||
{
|
||||
pd_error(x, "netreceive: got dollar sign in message");
|
||||
goto nodice;
|
||||
}
|
||||
if (at[msg].a_type == A_FLOAT)
|
||||
{
|
||||
if (emsg > msg + 1)
|
||||
outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg);
|
||||
else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float);
|
||||
}
|
||||
else if (at[msg].a_type == A_SYMBOL)
|
||||
outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol,
|
||||
emsg-msg-1, at + msg + 1);
|
||||
}
|
||||
nodice:
|
||||
msg = emsg + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void shell_read(t_shell *x, int fd)
|
||||
{
|
||||
char buf[INBUFSIZE];
|
||||
t_binbuf* bbuf = binbuf_new();
|
||||
int i;
|
||||
int readto =
|
||||
(x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
|
||||
int ret;
|
||||
|
||||
ret = read(fd, buf,INBUFSIZE-1);
|
||||
buf[ret] = '\0';
|
||||
|
||||
for (i=0;i<ret;i++)
|
||||
if (buf[i] == '\n') buf[i] = ';';
|
||||
if (ret < 0)
|
||||
{
|
||||
error("shell: pipe read error");
|
||||
sys_rmpollfn(fd);
|
||||
x->fdpipe[0] = -1;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
post("EOF on socket %d\n", fd);
|
||||
sys_rmpollfn(fd);
|
||||
x->fdpipe[0] = -1;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int natom;
|
||||
t_atom *at;
|
||||
binbuf_text(bbuf, buf, strlen(buf));
|
||||
|
||||
natom = binbuf_getnatom(bbuf);
|
||||
at = binbuf_getvec(bbuf);
|
||||
shell_doit(x,bbuf);
|
||||
}
|
||||
binbuf_free(bbuf);
|
||||
}
|
||||
|
||||
|
||||
static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at)
|
||||
{
|
||||
int i;
|
||||
char tmp[MAXPDSTRING];
|
||||
int size = 0;
|
||||
|
||||
if (x->fdinpipe[0] == -1) return; /* nothing to send to */
|
||||
|
||||
for (i=0;i<ac;i++) {
|
||||
atom_string(at,tmp+size,MAXPDSTRING - size);
|
||||
at++;
|
||||
size=strlen(tmp);
|
||||
tmp[size++] = ' ';
|
||||
}
|
||||
tmp[size-1] = '\0';
|
||||
post("sending %s",tmp);
|
||||
write(x->fdinpipe[0],tmp,strlen(tmp));
|
||||
}
|
||||
|
||||
static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at)
|
||||
{
|
||||
int i;
|
||||
char* argv[20];
|
||||
t_symbol* sym;
|
||||
|
||||
if (!strcmp(s->s_name,"send")) {
|
||||
post("send");
|
||||
shell_send(x,s,ac,at);
|
||||
return;
|
||||
}
|
||||
|
||||
argv[0] = s->s_name;
|
||||
|
||||
if (x->fdpipe[0] != -1) {
|
||||
post("shell: old process still running");
|
||||
kill(x->pid,SIGKILL);
|
||||
shell_cleanup(x);
|
||||
}
|
||||
|
||||
|
||||
if (pipe(x->fdpipe) < 0) {
|
||||
error("unable to create pipe");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe(x->fdinpipe) < 0) {
|
||||
error("unable to create input pipe");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sys_addpollfn(x->fdpipe[0],shell_read,x);
|
||||
|
||||
if (!(x->pid = fork())) {
|
||||
int status;
|
||||
char* cmd = getbytes(1024);
|
||||
char* tcmd = getbytes(1024);
|
||||
strcpy(cmd,s->s_name);
|
||||
|
||||
#if 0
|
||||
for (i=1;i<=ac;i++) {
|
||||
argv[i] = getbytes(255);
|
||||
atom_string(at,argv[i],255);
|
||||
/* post("argument %s",argv[i]); */
|
||||
at++;
|
||||
}
|
||||
argv[i] = 0;
|
||||
#endif
|
||||
for (i=1;i<=ac;i++) {
|
||||
atom_string(at,tcmd,255);
|
||||
strcat(cmd," ");
|
||||
strcat(cmd,tcmd);
|
||||
at++;
|
||||
}
|
||||
|
||||
|
||||
/* reassign stdout */
|
||||
dup2(x->fdpipe[1],1);
|
||||
dup2(x->fdinpipe[1],0);
|
||||
|
||||
/* drop privileges */
|
||||
drop_priority();
|
||||
seteuid(getuid()); /* lose setuid priveliges */
|
||||
|
||||
post("executing %s",cmd);
|
||||
system(cmd);
|
||||
// execvp(s->s_name,argv);
|
||||
exit(0);
|
||||
}
|
||||
x->x_del = 4;
|
||||
clock_delay(x->x_clock,x->x_del);
|
||||
|
||||
if (x->x_echo)
|
||||
outlet_anything(x->x_obj.ob_outlet, s, ac, at);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void shell_free(t_shell* x)
|
||||
{
|
||||
binbuf_free(x->x_binbuf);
|
||||
}
|
||||
|
||||
static void *shell_new(void)
|
||||
{
|
||||
t_shell *x = (t_shell *)pd_new(shell_class);
|
||||
|
||||
x->x_echo = 0;
|
||||
x->fdpipe[0] = -1;
|
||||
x->fdpipe[1] = -1;
|
||||
x->fdinpipe[0] = -1;
|
||||
x->fdinpipe[1] = -1;
|
||||
|
||||
x->sr_inhead = x->sr_intail = 0;
|
||||
if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");;
|
||||
|
||||
x->x_binbuf = binbuf_new();
|
||||
|
||||
outlet_new(&x->x_obj, &s_list);
|
||||
x->x_done = outlet_new(&x->x_obj, &s_bang);
|
||||
x->x_clock = clock_new(x, (t_method) shell_check);
|
||||
return (x);
|
||||
}
|
||||
|
||||
void shell_setup(void)
|
||||
{
|
||||
shell_class = class_new(gensym("shell"), (t_newmethod)shell_new,
|
||||
(t_method)shell_free,sizeof(t_shell), 0,0);
|
||||
class_addbang(shell_class,shell_bang);
|
||||
class_addanything(shell_class, shell_anything);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "../src/m_pd.h"
|
||||
#include "g_canvas.h" /* for widgetbehaviour */
|
||||
#include "fatom.h"
|
||||
|
||||
static t_class *slider_class;
|
||||
|
||||
static void slider_save(t_gobj *z, t_binbuf *b)
|
||||
{
|
||||
t_fatom *x = (t_fatom *)z;
|
||||
|
||||
binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
|
||||
x->x_obj.te_xpix, x->x_obj.te_ypix ,
|
||||
gensym("slider"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
|
||||
binbuf_addv(b, ";");
|
||||
}
|
||||
|
||||
|
||||
static void *slider_new(t_symbol* s,t_int argc, t_atom* argv)
|
||||
{
|
||||
t_fatom *x = (t_fatom *)pd_new(slider_class);
|
||||
x->x_type = gensym("vslider");
|
||||
return fatom_new(x,argc,argv);
|
||||
}
|
||||
|
||||
|
||||
t_widgetbehavior slider_widgetbehavior;
|
||||
|
||||
|
||||
void slider_setup(void) {
|
||||
slider_class = class_new(gensym("slider"), (t_newmethod)slider_new, 0,
|
||||
sizeof(t_fatom),0,A_GIMME,0);
|
||||
|
||||
slider_widgetbehavior.w_getrectfn = fatom_getrect;
|
||||
slider_widgetbehavior.w_displacefn = fatom_displace;
|
||||
slider_widgetbehavior.w_selectfn = fatom_select;
|
||||
slider_widgetbehavior.w_activatefn = fatom_activate;
|
||||
slider_widgetbehavior.w_deletefn = fatom_delete;
|
||||
slider_widgetbehavior.w_visfn= fatom_vis;
|
||||
slider_widgetbehavior.w_clickfn = NULL;
|
||||
|
||||
fatom_setup_common(slider_class);
|
||||
class_setwidget(slider_class,&slider_widgetbehavior);
|
||||
|
||||
#if PD_MINOR_VERSION < 37
|
||||
slider_widgetbehavior.w_savefn = slider_save;
|
||||
slider_widgetbehavior.w_propertiesfn = NULL;
|
||||
#else
|
||||
class_setsavefn(slider_class,&slider_save);
|
||||
class_setpropertiesfn(slider_class,&fatom_properties);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#include "../src/m_pd.h"
|
||||
#include "g_canvas.h"
|
||||
|
||||
|
||||
#ifdef NT
|
||||
#pragma warning( disable : 4244 )
|
||||
#pragma warning( disable : 4305 )
|
||||
#endif
|
||||
|
||||
#include "fatom.h"
|
||||
|
||||
/* can we use the normal text save function ?? */
|
||||
|
||||
static t_class *sliderh_class;
|
||||
|
||||
static void sliderh_save(t_gobj *z, t_binbuf *b)
|
||||
{
|
||||
|
||||
t_fatom *x = (t_fatom *)z;
|
||||
|
||||
binbuf_addv(b, "ssiisiiisss", gensym("#X"),gensym("obj"),
|
||||
x->x_obj.te_xpix, x->x_obj.te_ypix ,
|
||||
gensym("sliderh"),x->x_max,x->x_min,x->x_width,x->x_send,x->x_color,x->x_bgcolor);
|
||||
binbuf_addv(b, ";");
|
||||
}
|
||||
|
||||
|
||||
static void *sliderh_new(t_symbol* s, int argc, t_atom* argv)
|
||||
{
|
||||
t_fatom *x = (t_fatom *)pd_new(sliderh_class);
|
||||
x->x_type = gensym("hslider");
|
||||
return fatom_new(x,argc,argv);
|
||||
}
|
||||
|
||||
|
||||
t_widgetbehavior sliderh_widgetbehavior;
|
||||
|
||||
|
||||
|
||||
|
||||
void sliderh_setup(void) {
|
||||
sliderh_class = class_new(gensym("sliderh"), (t_newmethod)sliderh_new, 0,
|
||||
sizeof(t_fatom),0,A_DEFFLOAT,A_DEFFLOAT,A_DEFFLOAT,0);
|
||||
|
||||
fatom_setup_common(sliderh_class);
|
||||
|
||||
sliderh_widgetbehavior.w_getrectfn = fatom_getrect;
|
||||
sliderh_widgetbehavior.w_displacefn= fatom_displace;
|
||||
sliderh_widgetbehavior.w_selectfn= fatom_select;
|
||||
sliderh_widgetbehavior.w_activatefn=fatom_activate;
|
||||
sliderh_widgetbehavior.w_deletefn= fatom_delete;
|
||||
sliderh_widgetbehavior.w_visfn= fatom_vis;
|
||||
#if PD_MINOR_VERSION < 37
|
||||
sliderh_widgetbehavior.w_savefn= sliderh_save;
|
||||
sliderh_widgetbehavior.w_propertiesfn= NULL;
|
||||
#endif
|
||||
sliderh_widgetbehavior.w_clickfn= NULL;
|
||||
|
||||
class_setwidget(sliderh_class,&sliderh_widgetbehavior);
|
||||
#if PD_MINOR_VERSION >= 37
|
||||
class_setsavefn(sliderh_class,&sliderh_save);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#N canvas 0 0 240 300 10;
|
||||
#X obj 57 84 clip~ -0.1 0.1;
|
||||
#X obj 58 61 sig~;
|
||||
#X obj 57 111 snapshot~;
|
||||
#X floatatom 58 19 5 0 0 0 - - -;
|
||||
#X floatatom 57 144 5 0 0 0 - - -;
|
||||
#X obj 58 37 t f b;
|
||||
#X connect 0 0 2 0;
|
||||
#X connect 1 0 0 0;
|
||||
#X connect 2 0 4 0;
|
||||
#X connect 3 0 5 0;
|
||||
#X connect 5 0 1 0;
|
||||
#X connect 5 1 2 0;
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#N canvas 0 0 240 300 10;
|
||||
#X obj 38 93 noise~;
|
||||
#X obj 44 161 vcf~;
|
||||
#X obj 48 191 dac~;
|
||||
#X floatatom 138 33 5 0 0 0 - - -;
|
||||
#X obj 44 18 osc~ 1;
|
||||
#X obj 46 75 *~ 800;
|
||||
#X obj 48 48 +~ 2;
|
||||
#X obj 106 125 sig~;
|
||||
#X floatatom 132 77 5 0 0 0 - - -;
|
||||
#X connect 0 0 1 0;
|
||||
#X connect 1 0 2 0;
|
||||
#X connect 1 0 2 1;
|
||||
#X connect 3 0 1 2;
|
||||
#X connect 4 0 6 0;
|
||||
#X connect 6 0 5 0;
|
||||
#X connect 7 0 1 1;
|
||||
#X connect 8 0 7 0;
|
||||
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#include "../src/m_pd.h"
|
||||
#include <../src/m_fixed.h>
|
||||
|
||||
static t_class *sig_tilde_class;
|
||||
|
||||
typedef struct _sig
|
||||
{
|
||||
t_object x_obj;
|
||||
t_sample x_f;
|
||||
} t_sig;
|
||||
|
||||
static t_int *sig_tilde_perform(t_int *w)
|
||||
{
|
||||
t_sample f = *(t_sample *)(w[1]);
|
||||
t_sample *out = (t_sample *)(w[2]);
|
||||
int n = (int)(w[3]);
|
||||
while (n--)
|
||||
*out++ = f;
|
||||
return (w+4);
|
||||
}
|
||||
|
||||
static t_int *sig_tilde_perf8(t_int *w)
|
||||
{
|
||||
t_sample f = *(t_sample *)(w[1]);
|
||||
t_sample *out = (t_sample *)(w[2]);
|
||||
int n = (int)(w[3]);
|
||||
|
||||
for (; n; n -= 8, out += 8)
|
||||
{
|
||||
out[0] = f;
|
||||
out[1] = f;
|
||||
out[2] = f;
|
||||
out[3] = f;
|
||||
out[4] = f;
|
||||
out[5] = f;
|
||||
out[6] = f;
|
||||
out[7] = f;
|
||||
}
|
||||
return (w+4);
|
||||
}
|
||||
|
||||
|
||||
static void sig_tilde_float(t_sig *x, t_float f)
|
||||
{
|
||||
x->x_f = ftofix(f);
|
||||
}
|
||||
|
||||
static void sig_tilde_dsp(t_sig *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void *sig_tilde_new(t_floatarg f)
|
||||
{
|
||||
t_sig *x = (t_sig *)pd_new(sig_tilde_class);
|
||||
x->x_f = ftofix(f);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
return (x);
|
||||
}
|
||||
|
||||
void sig_tilde_setup(void)
|
||||
{
|
||||
sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
|
||||
sizeof(t_sig), 0, A_DEFFLOAT, 0);
|
||||
class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
|
||||
class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
# The compiler for iPod has a bug with -O6, thats why we try to compile twice
|
||||
|
||||
make CFLAGS="-O6 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi " -k ipod
|
||||
make CFLAGS="-O2 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi" ipod
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,319 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* send~, delread~, throw~, catch~ */
|
||||
|
||||
#include "m_pd.h"
|
||||
extern int ugen_getsortno(void);
|
||||
|
||||
#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
|
||||
static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
|
||||
|
||||
/* ----------------------------- delwrite~ ----------------------------- */
|
||||
static t_class *sigdelwrite_class;
|
||||
|
||||
typedef struct delwritectl
|
||||
{
|
||||
int c_n;
|
||||
float *c_vec;
|
||||
int c_phase;
|
||||
} t_delwritectl;
|
||||
|
||||
typedef struct _sigdelwrite
|
||||
{
|
||||
t_object x_obj;
|
||||
t_symbol *x_sym;
|
||||
t_delwritectl x_cspace;
|
||||
int x_sortno; /* DSP sort number at which this was last put on chain */
|
||||
int x_rsortno; /* DSP sort # for first delread or write in chain */
|
||||
int x_vecsize; /* vector size for delread~ to use */
|
||||
float x_f;
|
||||
} t_sigdelwrite;
|
||||
|
||||
#define XTRASAMPS 4
|
||||
#define SAMPBLK 4
|
||||
|
||||
/* routine to check that all delwrites/delreads/vds have same vecsize */
|
||||
static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
|
||||
{
|
||||
/*
|
||||
LATER this should really check sample rate and blocking, once that is
|
||||
supported. Probably we don't actually care about vecsize.
|
||||
For now just suppress this check... */
|
||||
#if 0
|
||||
if (x->x_rsortno != ugen_getsortno())
|
||||
{
|
||||
x->x_vecsize = vecsize;
|
||||
x->x_rsortno = ugen_getsortno();
|
||||
}
|
||||
else if (vecsize != x->x_vecsize)
|
||||
pd_error(x, "delread/delwrite/vd vector size mismatch");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
|
||||
{
|
||||
int nsamps;
|
||||
t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
|
||||
if (!*s->s_name) s = gensym("delwrite~");
|
||||
pd_bind(&x->x_obj.ob_pd, s);
|
||||
x->x_sym = s;
|
||||
nsamps = msec * sys_getsr() * (float)(0.001f);
|
||||
if (nsamps < 1) nsamps = 1;
|
||||
nsamps += ((- nsamps) & (SAMPBLK - 1));
|
||||
nsamps += DEFDELVS;
|
||||
x->x_cspace.c_n = nsamps;
|
||||
x->x_cspace.c_vec =
|
||||
(float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
|
||||
x->x_cspace.c_phase = XTRASAMPS;
|
||||
x->x_sortno = 0;
|
||||
x->x_vecsize = 0;
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigdelwrite_perform(t_int *w)
|
||||
{
|
||||
t_float *in = (t_float *)(w[1]);
|
||||
t_delwritectl *c = (t_delwritectl *)(w[2]);
|
||||
int n = (int)(w[3]);
|
||||
int phase = c->c_phase, nsamps = c->c_n;
|
||||
float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
|
||||
phase += n;
|
||||
while (n--)
|
||||
{
|
||||
float f = *in++;
|
||||
if (PD_BIGORSMALL(f))
|
||||
f = 0;
|
||||
*bp++ = f;
|
||||
if (bp == ep)
|
||||
{
|
||||
vp[0] = ep[-4];
|
||||
vp[1] = ep[-3];
|
||||
vp[2] = ep[-2];
|
||||
vp[3] = ep[-1];
|
||||
bp = vp + XTRASAMPS;
|
||||
phase -= nsamps;
|
||||
}
|
||||
}
|
||||
c->c_phase = phase;
|
||||
return (w+4);
|
||||
}
|
||||
|
||||
static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
|
||||
x->x_sortno = ugen_getsortno();
|
||||
sigdelwrite_checkvecsize(x, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void sigdelwrite_free(t_sigdelwrite *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, x->x_sym);
|
||||
freebytes(x->x_cspace.c_vec,
|
||||
(x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
|
||||
}
|
||||
|
||||
static void sigdelwrite_setup(void)
|
||||
{
|
||||
sigdelwrite_class = class_new(gensym("delwrite~"),
|
||||
(t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
|
||||
sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
|
||||
class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
|
||||
gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ----------------------------- delread~ ----------------------------- */
|
||||
static t_class *sigdelread_class;
|
||||
|
||||
typedef struct _sigdelread
|
||||
{
|
||||
t_object x_obj;
|
||||
t_symbol *x_sym;
|
||||
t_float x_deltime; /* delay in msec */
|
||||
int x_delsamps; /* delay in samples */
|
||||
t_float x_sr; /* samples per msec */
|
||||
t_float x_n; /* vector size */
|
||||
int x_zerodel; /* 0 or vecsize depending on read/write order */
|
||||
} t_sigdelread;
|
||||
|
||||
static void sigdelread_float(t_sigdelread *x, t_float f);
|
||||
|
||||
static void *sigdelread_new(t_symbol *s, t_floatarg f)
|
||||
{
|
||||
t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
|
||||
x->x_sym = s;
|
||||
x->x_sr = 1;
|
||||
x->x_n = 1;
|
||||
x->x_zerodel = 0;
|
||||
sigdelread_float(x, f);
|
||||
outlet_new(&x->x_obj, &s_signal);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void sigdelread_float(t_sigdelread *x, t_float f)
|
||||
{
|
||||
int samps;
|
||||
t_sigdelwrite *delwriter =
|
||||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
|
||||
x->x_deltime = f;
|
||||
if (delwriter)
|
||||
{
|
||||
int delsize = delwriter->x_cspace.c_n;
|
||||
x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
|
||||
+ x->x_n - x->x_zerodel;
|
||||
if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
|
||||
else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
|
||||
x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
|
||||
}
|
||||
}
|
||||
|
||||
static t_int *sigdelread_perform(t_int *w)
|
||||
{
|
||||
t_float *out = (t_float *)(w[1]);
|
||||
t_delwritectl *c = (t_delwritectl *)(w[2]);
|
||||
int delsamps = *(int *)(w[3]);
|
||||
int n = (int)(w[4]);
|
||||
int phase = c->c_phase - delsamps, nsamps = c->c_n;
|
||||
float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
|
||||
|
||||
if (phase < 0) phase += nsamps;
|
||||
bp = vp + phase;
|
||||
while (n--)
|
||||
{
|
||||
*out++ = *bp++;
|
||||
if (bp == ep) bp -= nsamps;
|
||||
}
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
|
||||
{
|
||||
t_sigdelwrite *delwriter =
|
||||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
|
||||
x->x_sr = sp[0]->s_sr * 0.001;
|
||||
x->x_n = sp[0]->s_n;
|
||||
if (delwriter)
|
||||
{
|
||||
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
|
||||
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
|
||||
0 : delwriter->x_vecsize);
|
||||
sigdelread_float(x, x->x_deltime);
|
||||
dsp_add(sigdelread_perform, 4,
|
||||
sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
|
||||
}
|
||||
else if (*x->x_sym->s_name)
|
||||
error("delread~: %s: no such delwrite~",x->x_sym->s_name);
|
||||
}
|
||||
|
||||
static void sigdelread_setup(void)
|
||||
{
|
||||
sigdelread_class = class_new(gensym("delread~"),
|
||||
(t_newmethod)sigdelread_new, 0,
|
||||
sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
|
||||
class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
|
||||
gensym("dsp"), 0);
|
||||
class_addfloat(sigdelread_class, (t_method)sigdelread_float);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------- vd~ ----------------------------- */
|
||||
static t_class *sigvd_class;
|
||||
|
||||
typedef struct _sigvd
|
||||
{
|
||||
t_object x_obj;
|
||||
t_symbol *x_sym;
|
||||
t_float x_sr; /* samples per msec */
|
||||
int x_zerodel; /* 0 or vecsize depending on read/write order */
|
||||
float x_f;
|
||||
} t_sigvd;
|
||||
|
||||
static void *sigvd_new(t_symbol *s)
|
||||
{
|
||||
t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
|
||||
if (!*s->s_name) s = gensym("vd~");
|
||||
x->x_sym = s;
|
||||
x->x_sr = 1;
|
||||
x->x_zerodel = 0;
|
||||
outlet_new(&x->x_obj, &s_signal);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigvd_perform(t_int *w)
|
||||
{
|
||||
t_float *in = (t_float *)(w[1]);
|
||||
t_float *out = (t_float *)(w[2]);
|
||||
t_delwritectl *ctl = (t_delwritectl *)(w[3]);
|
||||
t_sigvd *x = (t_sigvd *)(w[4]);
|
||||
int n = (int)(w[5]);
|
||||
|
||||
int nsamps = ctl->c_n;
|
||||
float limit = nsamps - n - 1;
|
||||
float fn = n-1;
|
||||
float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
|
||||
float zerodel = x->x_zerodel;
|
||||
while (n--)
|
||||
{
|
||||
float delsamps = x->x_sr * *in++ - zerodel, frac;
|
||||
int idelsamps;
|
||||
float a, b, c, d, cminusb;
|
||||
if (delsamps < 1.00001f) delsamps = 1.00001f;
|
||||
if (delsamps > limit) delsamps = limit;
|
||||
delsamps += fn;
|
||||
fn = fn - 1.0f;
|
||||
idelsamps = delsamps;
|
||||
frac = delsamps - (float)idelsamps;
|
||||
bp = wp - idelsamps;
|
||||
if (bp < vp + 4) bp += nsamps;
|
||||
d = bp[-3];
|
||||
c = bp[-2];
|
||||
b = bp[-1];
|
||||
a = bp[0];
|
||||
cminusb = c-b;
|
||||
*out++ = b + frac * (
|
||||
cminusb - 0.1666667f * (1.-frac) * (
|
||||
(d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
|
||||
)
|
||||
);
|
||||
}
|
||||
return (w+6);
|
||||
}
|
||||
|
||||
static void sigvd_dsp(t_sigvd *x, t_signal **sp)
|
||||
{
|
||||
t_sigdelwrite *delwriter =
|
||||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
|
||||
x->x_sr = sp[0]->s_sr * 0.001;
|
||||
if (delwriter)
|
||||
{
|
||||
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
|
||||
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
|
||||
0 : delwriter->x_vecsize);
|
||||
dsp_add(sigvd_perform, 5,
|
||||
sp[0]->s_vec, sp[1]->s_vec,
|
||||
&delwriter->x_cspace, x, sp[0]->s_n);
|
||||
}
|
||||
else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
|
||||
}
|
||||
|
||||
static void sigvd_setup(void)
|
||||
{
|
||||
sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
|
||||
sizeof(t_sigvd), 0, A_DEFSYM, 0);
|
||||
class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
|
||||
CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
|
||||
}
|
||||
|
||||
/* ----------------------- global setup routine ---------------- */
|
||||
|
||||
void d_delay_setup(void)
|
||||
{
|
||||
sigdelwrite_setup();
|
||||
sigdelread_setup();
|
||||
sigvd_setup();
|
||||
}
|
||||
|
||||
|
|
@ -1,548 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* "filters", both linear and nonlinear.
|
||||
*/
|
||||
#include "m_pd.h"
|
||||
#include <math.h>
|
||||
|
||||
/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
|
||||
|
||||
typedef struct hipctl
|
||||
{
|
||||
float c_x;
|
||||
float c_coef;
|
||||
} t_hipctl;
|
||||
|
||||
typedef struct sighip
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_sr;
|
||||
float x_hz;
|
||||
t_hipctl x_cspace;
|
||||
t_hipctl *x_ctl;
|
||||
float x_f;
|
||||
} t_sighip;
|
||||
|
||||
t_class *sighip_class;
|
||||
static void sighip_ft1(t_sighip *x, t_floatarg f);
|
||||
|
||||
static void *sighip_new(t_floatarg f)
|
||||
{
|
||||
t_sighip *x = (t_sighip *)pd_new(sighip_class);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_sr = 44100;
|
||||
x->x_ctl = &x->x_cspace;
|
||||
x->x_cspace.c_x = 0;
|
||||
sighip_ft1(x, f);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void sighip_ft1(t_sighip *x, t_floatarg f)
|
||||
{
|
||||
if (f < 0) f = 0;
|
||||
x->x_hz = f;
|
||||
x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
|
||||
if (x->x_ctl->c_coef < 0)
|
||||
x->x_ctl->c_coef = 0;
|
||||
else if (x->x_ctl->c_coef > 1)
|
||||
x->x_ctl->c_coef = 1;
|
||||
}
|
||||
|
||||
static t_int *sighip_perform(t_int *w)
|
||||
{
|
||||
float *in = (float *)(w[1]);
|
||||
float *out = (float *)(w[2]);
|
||||
t_hipctl *c = (t_hipctl *)(w[3]);
|
||||
int n = (t_int)(w[4]);
|
||||
int i;
|
||||
float last = c->c_x;
|
||||
float coef = c->c_coef;
|
||||
if (coef < 1)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float new = *in++ + coef * last;
|
||||
*out++ = new - last;
|
||||
last = new;
|
||||
}
|
||||
if (PD_BIGORSMALL(last))
|
||||
last = 0;
|
||||
c->c_x = last;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
*out++ = *in++;
|
||||
c->c_x = 0;
|
||||
}
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void sighip_dsp(t_sighip *x, t_signal **sp)
|
||||
{
|
||||
x->x_sr = sp[0]->s_sr;
|
||||
sighip_ft1(x, x->x_hz);
|
||||
dsp_add(sighip_perform, 4,
|
||||
sp[0]->s_vec, sp[1]->s_vec,
|
||||
x->x_ctl, sp[0]->s_n);
|
||||
|
||||
}
|
||||
|
||||
static void sighip_clear(t_sighip *x, t_floatarg q)
|
||||
{
|
||||
x->x_cspace.c_x = 0;
|
||||
}
|
||||
|
||||
void sighip_setup(void)
|
||||
{
|
||||
sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
|
||||
sizeof(t_sighip), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
|
||||
class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(sighip_class, (t_method)sighip_ft1,
|
||||
gensym("ft1"), A_FLOAT, 0);
|
||||
class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
|
||||
}
|
||||
|
||||
/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
|
||||
|
||||
typedef struct lopctl
|
||||
{
|
||||
float c_x;
|
||||
float c_coef;
|
||||
} t_lopctl;
|
||||
|
||||
typedef struct siglop
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_sr;
|
||||
float x_hz;
|
||||
t_lopctl x_cspace;
|
||||
t_lopctl *x_ctl;
|
||||
float x_f;
|
||||
} t_siglop;
|
||||
|
||||
t_class *siglop_class;
|
||||
|
||||
static void siglop_ft1(t_siglop *x, t_floatarg f);
|
||||
|
||||
static void *siglop_new(t_floatarg f)
|
||||
{
|
||||
t_siglop *x = (t_siglop *)pd_new(siglop_class);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_sr = 44100;
|
||||
x->x_ctl = &x->x_cspace;
|
||||
x->x_cspace.c_x = 0;
|
||||
siglop_ft1(x, f);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void siglop_ft1(t_siglop *x, t_floatarg f)
|
||||
{
|
||||
if (f < 0) f = 0;
|
||||
x->x_hz = f;
|
||||
x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
|
||||
if (x->x_ctl->c_coef > 1)
|
||||
x->x_ctl->c_coef = 1;
|
||||
else if (x->x_ctl->c_coef < 0)
|
||||
x->x_ctl->c_coef = 0;
|
||||
}
|
||||
|
||||
static void siglop_clear(t_siglop *x, t_floatarg q)
|
||||
{
|
||||
x->x_cspace.c_x = 0;
|
||||
}
|
||||
|
||||
static t_int *siglop_perform(t_int *w)
|
||||
{
|
||||
float *in = (float *)(w[1]);
|
||||
float *out = (float *)(w[2]);
|
||||
t_lopctl *c = (t_lopctl *)(w[3]);
|
||||
int n = (t_int)(w[4]);
|
||||
int i;
|
||||
float last = c->c_x;
|
||||
float coef = c->c_coef;
|
||||
float feedback = 1 - coef;
|
||||
for (i = 0; i < n; i++)
|
||||
last = *out++ = coef * *in++ + feedback * last;
|
||||
if (PD_BIGORSMALL(last))
|
||||
last = 0;
|
||||
c->c_x = last;
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void siglop_dsp(t_siglop *x, t_signal **sp)
|
||||
{
|
||||
x->x_sr = sp[0]->s_sr;
|
||||
siglop_ft1(x, x->x_hz);
|
||||
dsp_add(siglop_perform, 4,
|
||||
sp[0]->s_vec, sp[1]->s_vec,
|
||||
x->x_ctl, sp[0]->s_n);
|
||||
|
||||
}
|
||||
|
||||
void siglop_setup(void)
|
||||
{
|
||||
siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
|
||||
sizeof(t_siglop), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
|
||||
class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(siglop_class, (t_method)siglop_ft1,
|
||||
gensym("ft1"), A_FLOAT, 0);
|
||||
class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
|
||||
}
|
||||
|
||||
/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
|
||||
|
||||
typedef struct bpctl
|
||||
{
|
||||
float c_x1;
|
||||
float c_x2;
|
||||
float c_coef1;
|
||||
float c_coef2;
|
||||
float c_gain;
|
||||
} t_bpctl;
|
||||
|
||||
typedef struct sigbp
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_sr;
|
||||
float x_freq;
|
||||
float x_q;
|
||||
t_bpctl x_cspace;
|
||||
t_bpctl *x_ctl;
|
||||
float x_f;
|
||||
} t_sigbp;
|
||||
|
||||
t_class *sigbp_class;
|
||||
|
||||
static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
|
||||
|
||||
static void *sigbp_new(t_floatarg f, t_floatarg q)
|
||||
{
|
||||
t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_sr = 44100;
|
||||
x->x_ctl = &x->x_cspace;
|
||||
x->x_cspace.c_x1 = 0;
|
||||
x->x_cspace.c_x2 = 0;
|
||||
sigbp_docoef(x, f, q);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static float sigbp_qcos(float f)
|
||||
{
|
||||
if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
|
||||
{
|
||||
float g = f*f;
|
||||
return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
|
||||
}
|
||||
else return (0);
|
||||
}
|
||||
|
||||
static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
|
||||
{
|
||||
float r, oneminusr, omega;
|
||||
if (f < 0.001) f = 10;
|
||||
if (q < 0) q = 0;
|
||||
x->x_freq = f;
|
||||
x->x_q = q;
|
||||
omega = f * (2.0f * 3.14159f) / x->x_sr;
|
||||
if (q < 0.001) oneminusr = 1.0f;
|
||||
else oneminusr = omega/q;
|
||||
if (oneminusr > 1.0f) oneminusr = 1.0f;
|
||||
r = 1.0f - oneminusr;
|
||||
x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
|
||||
x->x_ctl->c_coef2 = - r * r;
|
||||
x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
|
||||
/* post("r %f, omega %f, coef1 %f, coef2 %f",
|
||||
r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
|
||||
}
|
||||
|
||||
static void sigbp_ft1(t_sigbp *x, t_floatarg f)
|
||||
{
|
||||
sigbp_docoef(x, f, x->x_q);
|
||||
}
|
||||
|
||||
static void sigbp_ft2(t_sigbp *x, t_floatarg q)
|
||||
{
|
||||
sigbp_docoef(x, x->x_freq, q);
|
||||
}
|
||||
|
||||
static void sigbp_clear(t_sigbp *x, t_floatarg q)
|
||||
{
|
||||
x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
|
||||
}
|
||||
|
||||
static t_int *sigbp_perform(t_int *w)
|
||||
{
|
||||
float *in = (float *)(w[1]);
|
||||
float *out = (float *)(w[2]);
|
||||
t_bpctl *c = (t_bpctl *)(w[3]);
|
||||
int n = (t_int)(w[4]);
|
||||
int i;
|
||||
float last = c->c_x1;
|
||||
float prev = c->c_x2;
|
||||
float coef1 = c->c_coef1;
|
||||
float coef2 = c->c_coef2;
|
||||
float gain = c->c_gain;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float output = *in++ + coef1 * last + coef2 * prev;
|
||||
*out++ = gain * output;
|
||||
prev = last;
|
||||
last = output;
|
||||
}
|
||||
if (PD_BIGORSMALL(last))
|
||||
last = 0;
|
||||
if (PD_BIGORSMALL(prev))
|
||||
prev = 0;
|
||||
c->c_x1 = last;
|
||||
c->c_x2 = prev;
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void sigbp_dsp(t_sigbp *x, t_signal **sp)
|
||||
{
|
||||
x->x_sr = sp[0]->s_sr;
|
||||
sigbp_docoef(x, x->x_freq, x->x_q);
|
||||
dsp_add(sigbp_perform, 4,
|
||||
sp[0]->s_vec, sp[1]->s_vec,
|
||||
x->x_ctl, sp[0]->s_n);
|
||||
|
||||
}
|
||||
|
||||
void sigbp_setup(void)
|
||||
{
|
||||
sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
|
||||
sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
|
||||
class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(sigbp_class, (t_method)sigbp_ft1,
|
||||
gensym("ft1"), A_FLOAT, 0);
|
||||
class_addmethod(sigbp_class, (t_method)sigbp_ft2,
|
||||
gensym("ft2"), A_FLOAT, 0);
|
||||
class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
|
||||
}
|
||||
|
||||
/* ---------------- biquad~ - raw biquad filter ----------------- */
|
||||
|
||||
typedef struct biquadctl
|
||||
{
|
||||
float c_x1;
|
||||
float c_x2;
|
||||
float c_fb1;
|
||||
float c_fb2;
|
||||
float c_ff1;
|
||||
float c_ff2;
|
||||
float c_ff3;
|
||||
} t_biquadctl;
|
||||
|
||||
typedef struct sigbiquad
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
t_biquadctl x_cspace;
|
||||
t_biquadctl *x_ctl;
|
||||
} t_sigbiquad;
|
||||
|
||||
t_class *sigbiquad_class;
|
||||
|
||||
static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
|
||||
|
||||
static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_ctl = &x->x_cspace;
|
||||
x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
|
||||
sigbiquad_list(x, s, argc, argv);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigbiquad_perform(t_int *w)
|
||||
{
|
||||
float *in = (float *)(w[1]);
|
||||
float *out = (float *)(w[2]);
|
||||
t_biquadctl *c = (t_biquadctl *)(w[3]);
|
||||
int n = (t_int)(w[4]);
|
||||
int i;
|
||||
float last = c->c_x1;
|
||||
float prev = c->c_x2;
|
||||
float fb1 = c->c_fb1;
|
||||
float fb2 = c->c_fb2;
|
||||
float ff1 = c->c_ff1;
|
||||
float ff2 = c->c_ff2;
|
||||
float ff3 = c->c_ff3;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float output = *in++ + fb1 * last + fb2 * prev;
|
||||
if (PD_BIGORSMALL(output))
|
||||
output = 0;
|
||||
*out++ = ff1 * output + ff2 * last + ff3 * prev;
|
||||
prev = last;
|
||||
last = output;
|
||||
}
|
||||
c->c_x1 = last;
|
||||
c->c_x2 = prev;
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
float fb1 = atom_getfloatarg(0, argc, argv);
|
||||
float fb2 = atom_getfloatarg(1, argc, argv);
|
||||
float ff1 = atom_getfloatarg(2, argc, argv);
|
||||
float ff2 = atom_getfloatarg(3, argc, argv);
|
||||
float ff3 = atom_getfloatarg(4, argc, argv);
|
||||
float discriminant = fb1 * fb1 + 4 * fb2;
|
||||
t_biquadctl *c = x->x_ctl;
|
||||
if (discriminant < 0) /* imaginary roots -- resonant filter */
|
||||
{
|
||||
/* they're conjugates so we just check that the product
|
||||
is less than one */
|
||||
if (fb2 >= -1.0f) goto stable;
|
||||
}
|
||||
else /* real roots */
|
||||
{
|
||||
/* check that the parabola 1 - fb1 x - fb2 x^2 has a
|
||||
vertex between -1 and 1, and that it's nonnegative
|
||||
at both ends, which implies both roots are in [1-,1]. */
|
||||
if (fb1 <= 2.0f && fb1 >= -2.0f &&
|
||||
1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
|
||||
goto stable;
|
||||
}
|
||||
/* if unstable, just bash to zero */
|
||||
fb1 = fb2 = ff1 = ff2 = ff3 = 0;
|
||||
stable:
|
||||
c->c_fb1 = fb1;
|
||||
c->c_fb2 = fb2;
|
||||
c->c_ff1 = ff1;
|
||||
c->c_ff2 = ff2;
|
||||
c->c_ff3 = ff3;
|
||||
}
|
||||
|
||||
static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
t_biquadctl *c = x->x_ctl;
|
||||
c->c_x1 = atom_getfloatarg(0, argc, argv);
|
||||
c->c_x2 = atom_getfloatarg(1, argc, argv);
|
||||
}
|
||||
|
||||
static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigbiquad_perform, 4,
|
||||
sp[0]->s_vec, sp[1]->s_vec,
|
||||
x->x_ctl, sp[0]->s_n);
|
||||
|
||||
}
|
||||
|
||||
void sigbiquad_setup(void)
|
||||
{
|
||||
sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
|
||||
0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
|
||||
CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
|
||||
class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
|
||||
class_addlist(sigbiquad_class, sigbiquad_list);
|
||||
class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
|
||||
A_GIMME, 0);
|
||||
class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
|
||||
A_GIMME, 0);
|
||||
}
|
||||
|
||||
/* ---------------- samphold~ - sample and hold ----------------- */
|
||||
|
||||
typedef struct sigsamphold
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
float x_lastin;
|
||||
float x_lastout;
|
||||
} t_sigsamphold;
|
||||
|
||||
t_class *sigsamphold_class;
|
||||
|
||||
static void *sigsamphold_new(void)
|
||||
{
|
||||
t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_lastin = 0;
|
||||
x->x_lastout = 0;
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigsamphold_perform(t_int *w)
|
||||
{
|
||||
float *in1 = (float *)(w[1]);
|
||||
float *in2 = (float *)(w[2]);
|
||||
float *out = (float *)(w[3]);
|
||||
t_sigsamphold *x = (t_sigsamphold *)(w[4]);
|
||||
int n = (t_int)(w[5]);
|
||||
int i;
|
||||
float lastin = x->x_lastin;
|
||||
float lastout = x->x_lastout;
|
||||
for (i = 0; i < n; i++, *in1++)
|
||||
{
|
||||
float next = *in2++;
|
||||
if (next < lastin) lastout = *in1;
|
||||
*out++ = lastout;
|
||||
lastin = next;
|
||||
}
|
||||
x->x_lastin = lastin;
|
||||
x->x_lastout = lastout;
|
||||
return (w+6);
|
||||
}
|
||||
|
||||
static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigsamphold_perform, 5,
|
||||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
|
||||
x, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void sigsamphold_reset(t_sigsamphold *x)
|
||||
{
|
||||
x->x_lastin = 1e20;
|
||||
}
|
||||
|
||||
static void sigsamphold_set(t_sigsamphold *x, t_float f)
|
||||
{
|
||||
x->x_lastout = f;
|
||||
}
|
||||
|
||||
void sigsamphold_setup(void)
|
||||
{
|
||||
sigsamphold_class = class_new(gensym("samphold~"),
|
||||
(t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
|
||||
CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
|
||||
class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
|
||||
gensym("set"), A_FLOAT, 0);
|
||||
class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
|
||||
gensym("reset"), 0);
|
||||
class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
|
||||
gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------ setup routine ------------------------- */
|
||||
|
||||
void d_filter_setup(void)
|
||||
{
|
||||
sighip_setup();
|
||||
siglop_setup();
|
||||
sigbp_setup();
|
||||
sigbiquad_setup();
|
||||
sigsamphold_setup();
|
||||
}
|
||||
|
||||
|
|
@ -1,573 +0,0 @@
|
|||
/* Copyright (c) 1997-2001 Miller Puckette and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* mathematical functions and other transfer functions, including tilde
|
||||
versions of stuff from x_acoustics.c.
|
||||
*/
|
||||
|
||||
#include "m_pd.h"
|
||||
#include <math.h>
|
||||
#define LOGTEN 2.302585092994
|
||||
|
||||
/* ------------------------- clip~ -------------------------- */
|
||||
static t_class *clip_class;
|
||||
|
||||
typedef struct _clip
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
t_sample x_lo;
|
||||
t_sample x_hi;
|
||||
} t_clip;
|
||||
|
||||
static void *clip_new(t_floatarg lo, t_floatarg hi)
|
||||
{
|
||||
t_clip *x = (t_clip *)pd_new(clip_class);
|
||||
x->x_lo = lo;
|
||||
x->x_hi = hi;
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
floatinlet_new(&x->x_obj, &x->x_lo);
|
||||
floatinlet_new(&x->x_obj, &x->x_hi);
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *clip_perform(t_int *w)
|
||||
{
|
||||
t_clip *x = (t_clip *)(w[1]);
|
||||
t_float *in = (t_float *)(w[2]);
|
||||
t_float *out = (t_float *)(w[3]);
|
||||
int n = (int)(w[4]);
|
||||
while (n--)
|
||||
{
|
||||
float f = *in++;
|
||||
if (f < x->x_lo) f = x->x_lo;
|
||||
if (f > x->x_hi) f = x->x_hi;
|
||||
*out++ = f;
|
||||
}
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void clip_dsp(t_clip *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void clip_setup(void)
|
||||
{
|
||||
clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
|
||||
sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
|
||||
class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
|
||||
|
||||
#define DUMTAB1SIZE 256
|
||||
#define DUMTAB2SIZE 1024
|
||||
|
||||
static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
|
||||
|
||||
static void init_rsqrt(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DUMTAB1SIZE; i++)
|
||||
{
|
||||
float f;
|
||||
long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
|
||||
*(long *)(&f) = l;
|
||||
rsqrt_exptab[i] = 1./sqrt(f);
|
||||
}
|
||||
for (i = 0; i < DUMTAB2SIZE; i++)
|
||||
{
|
||||
float f = 1 + (1./DUMTAB2SIZE) * i;
|
||||
rsqrt_mantissatab[i] = 1./sqrt(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* these are used in externs like "bonk" */
|
||||
|
||||
float q8_rsqrt(float f)
|
||||
{
|
||||
long l = *(long *)(&f);
|
||||
if (f < 0) return (0);
|
||||
else return (rsqrt_exptab[(l >> 23) & 0xff] *
|
||||
rsqrt_mantissatab[(l >> 13) & 0x3ff]);
|
||||
}
|
||||
|
||||
float q8_sqrt(float f)
|
||||
{
|
||||
long l = *(long *)(&f);
|
||||
if (f < 0) return (0);
|
||||
else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
|
||||
rsqrt_mantissatab[(l >> 13) & 0x3ff]);
|
||||
}
|
||||
|
||||
/* the old names are OK unless we're in IRIX N32 */
|
||||
|
||||
#ifndef N32
|
||||
float qsqrt(float f) {return (q8_sqrt(f)); }
|
||||
float qrsqrt(float f) {return (q8_rsqrt(f)); }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct sigrsqrt
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_sigrsqrt;
|
||||
|
||||
static t_class *sigrsqrt_class;
|
||||
|
||||
static void *sigrsqrt_new(void)
|
||||
{
|
||||
t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigrsqrt_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
while (n--)
|
||||
{
|
||||
float f = *in;
|
||||
long l = *(long *)(in++);
|
||||
if (f < 0) *out++ = 0;
|
||||
else
|
||||
{
|
||||
float g = rsqrt_exptab[(l >> 23) & 0xff] *
|
||||
rsqrt_mantissatab[(l >> 13) & 0x3ff];
|
||||
*out++ = 1.5 * g - 0.5 * g * g * g * f;
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void sigrsqrt_setup(void)
|
||||
{
|
||||
init_rsqrt();
|
||||
sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
|
||||
sizeof(t_sigrsqrt), 0, 0);
|
||||
/* an old name for it: */
|
||||
class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
|
||||
CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
|
||||
class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
|
||||
/* sigsqrt - square root good to 8 mantissa bits */
|
||||
|
||||
typedef struct sigsqrt
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_sigsqrt;
|
||||
|
||||
static t_class *sigsqrt_class;
|
||||
|
||||
static void *sigsqrt_new(void)
|
||||
{
|
||||
t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
while (n--)
|
||||
{
|
||||
float f = *in;
|
||||
long l = *(long *)(in++);
|
||||
if (f < 0) *out++ = 0;
|
||||
else
|
||||
{
|
||||
float g = rsqrt_exptab[(l >> 23) & 0xff] *
|
||||
rsqrt_mantissatab[(l >> 13) & 0x3ff];
|
||||
*out++ = f * (1.5 * g - 0.5 * g * g * g * f);
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void sigsqrt_setup(void)
|
||||
{
|
||||
sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
|
||||
sizeof(t_sigsqrt), 0, 0);
|
||||
class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
|
||||
CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
|
||||
class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ wrap~ -------------------------- */
|
||||
|
||||
typedef struct wrap
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_sigwrap;
|
||||
|
||||
t_class *sigwrap_class;
|
||||
|
||||
static void *sigwrap_new(void)
|
||||
{
|
||||
t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *sigwrap_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
while (n--)
|
||||
{
|
||||
float f = *in++;
|
||||
int k = f;
|
||||
if (f > 0) *out++ = f-k;
|
||||
else *out++ = f - (k-1);
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void sigwrap_setup(void)
|
||||
{
|
||||
sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
|
||||
sizeof(t_sigwrap), 0, 0);
|
||||
CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
|
||||
class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ mtof_tilde~ -------------------------- */
|
||||
|
||||
typedef struct mtof_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_mtof_tilde;
|
||||
|
||||
t_class *mtof_tilde_class;
|
||||
|
||||
static void *mtof_tilde_new(void)
|
||||
{
|
||||
t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *mtof_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
if (f <= -1500) *out = 0;
|
||||
else
|
||||
{
|
||||
if (f > 1499) f = 1499;
|
||||
*out = 8.17579891564 * exp(.0577622650 * f);
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void mtof_tilde_setup(void)
|
||||
{
|
||||
mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
|
||||
sizeof(t_mtof_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
|
||||
class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ ftom_tilde~ -------------------------- */
|
||||
|
||||
typedef struct ftom_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_ftom_tilde;
|
||||
|
||||
t_class *ftom_tilde_class;
|
||||
|
||||
static void *ftom_tilde_new(void)
|
||||
{
|
||||
t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *ftom_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; *in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
*out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void ftom_tilde_setup(void)
|
||||
{
|
||||
ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
|
||||
sizeof(t_ftom_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
|
||||
class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ dbtorms~ -------------------------- */
|
||||
|
||||
typedef struct dbtorms_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_dbtorms_tilde;
|
||||
|
||||
t_class *dbtorms_tilde_class;
|
||||
|
||||
static void *dbtorms_tilde_new(void)
|
||||
{
|
||||
t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *dbtorms_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
if (f <= 0) *out = 0;
|
||||
else
|
||||
{
|
||||
if (f > 485)
|
||||
f = 485;
|
||||
*out = exp((LOGTEN * 0.05) * (f-100.));
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void dbtorms_tilde_setup(void)
|
||||
{
|
||||
dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
|
||||
sizeof(t_dbtorms_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
|
||||
class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ rmstodb~ -------------------------- */
|
||||
|
||||
typedef struct rmstodb_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_rmstodb_tilde;
|
||||
|
||||
t_class *rmstodb_tilde_class;
|
||||
|
||||
static void *rmstodb_tilde_new(void)
|
||||
{
|
||||
t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *rmstodb_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
if (f <= 0) *out = 0;
|
||||
else
|
||||
{
|
||||
float g = 100 + 20./LOGTEN * log(f);
|
||||
*out = (g < 0 ? 0 : g);
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void rmstodb_tilde_setup(void)
|
||||
{
|
||||
rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
|
||||
sizeof(t_rmstodb_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
|
||||
class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ dbtopow~ -------------------------- */
|
||||
|
||||
typedef struct dbtopow_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_dbtopow_tilde;
|
||||
|
||||
t_class *dbtopow_tilde_class;
|
||||
|
||||
static void *dbtopow_tilde_new(void)
|
||||
{
|
||||
t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *dbtopow_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
if (f <= 0) *out = 0;
|
||||
else
|
||||
{
|
||||
if (f > 870)
|
||||
f = 870;
|
||||
*out = exp((LOGTEN * 0.1) * (f-100.));
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void dbtopow_tilde_setup(void)
|
||||
{
|
||||
dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
|
||||
sizeof(t_dbtopow_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
|
||||
class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
/* ------------------------------ powtodb~ -------------------------- */
|
||||
|
||||
typedef struct powtodb_tilde
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_powtodb_tilde;
|
||||
|
||||
t_class *powtodb_tilde_class;
|
||||
|
||||
static void *powtodb_tilde_new(void)
|
||||
{
|
||||
t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *powtodb_tilde_perform(t_int *w)
|
||||
{
|
||||
float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
|
||||
t_int n = *(t_int *)(w+3);
|
||||
for (; n--; in++, out++)
|
||||
{
|
||||
float f = *in;
|
||||
if (f <= 0) *out = 0;
|
||||
else
|
||||
{
|
||||
float g = 100 + 10./LOGTEN * log(f);
|
||||
*out = (g < 0 ? 0 : g);
|
||||
}
|
||||
}
|
||||
return (w + 4);
|
||||
}
|
||||
|
||||
static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
void powtodb_tilde_setup(void)
|
||||
{
|
||||
powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
|
||||
sizeof(t_powtodb_tilde), 0, 0);
|
||||
CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
|
||||
class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ global setup routine ------------------------- */
|
||||
|
||||
void d_math_setup(void)
|
||||
{
|
||||
t_symbol *s = gensym("acoustics~.pd");
|
||||
clip_setup();
|
||||
sigrsqrt_setup();
|
||||
sigsqrt_setup();
|
||||
sigwrap_setup();
|
||||
mtof_tilde_setup();
|
||||
ftom_tilde_setup();
|
||||
dbtorms_tilde_setup();
|
||||
rmstodb_tilde_setup();
|
||||
dbtopow_tilde_setup();
|
||||
powtodb_tilde_setup();
|
||||
|
||||
class_sethelpsymbol(mtof_tilde_class, s);
|
||||
class_sethelpsymbol(ftom_tilde_class, s);
|
||||
class_sethelpsymbol(dbtorms_tilde_class, s);
|
||||
class_sethelpsymbol(rmstodb_tilde_class, s);
|
||||
class_sethelpsymbol(dbtopow_tilde_class, s);
|
||||
class_sethelpsymbol(powtodb_tilde_class, s);
|
||||
}
|
||||
|
||||
|
|
@ -1,535 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
|
||||
*/
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "math.h"
|
||||
|
||||
#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
|
||||
|
||||
/* machine-dependent definitions. These ifdefs really
|
||||
should have been by CPU type and not by operating system! */
|
||||
#ifdef IRIX
|
||||
/* big-endian. Most significant byte is at low address in memory */
|
||||
#define HIOFFSET 0 /* word offset to find MSB */
|
||||
#define LOWOFFSET 1 /* word offset to find LSB */
|
||||
#define int32 long /* a data type that has 32 bits */
|
||||
#else
|
||||
#ifdef MSW
|
||||
/* little-endian; most significant byte is at highest address */
|
||||
#define HIOFFSET 1
|
||||
#define LOWOFFSET 0
|
||||
#define int32 long
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/endian.h>
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define HIOFFSET 1
|
||||
#define LOWOFFSET 0
|
||||
#else
|
||||
#define HIOFFSET 0 /* word offset to find MSB */
|
||||
#define LOWOFFSET 1 /* word offset to find LSB */
|
||||
#endif /* BYTE_ORDER */
|
||||
#include <sys/types.h>
|
||||
#define int32 int32_t
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
|
||||
#error No byte order defined
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define HIOFFSET 1
|
||||
#define LOWOFFSET 0
|
||||
#else
|
||||
#define HIOFFSET 0 /* word offset to find MSB */
|
||||
#define LOWOFFSET 1 /* word offset to find LSB */
|
||||
#endif /* __BYTE_ORDER */
|
||||
|
||||
#include <sys/types.h>
|
||||
#define int32 int32_t
|
||||
|
||||
#else
|
||||
#ifdef MACOSX
|
||||
#define HIOFFSET 0 /* word offset to find MSB */
|
||||
#define LOWOFFSET 1 /* word offset to find LSB */
|
||||
#define int32 int /* a data type that has 32 bits */
|
||||
|
||||
#endif /* MACOSX */
|
||||
#endif /* __linux__ */
|
||||
#endif /* MSW */
|
||||
#endif /* SGI */
|
||||
|
||||
union tabfudge
|
||||
{
|
||||
double tf_d;
|
||||
int32 tf_i[2];
|
||||
};
|
||||
|
||||
|
||||
/* -------------------------- phasor~ ------------------------------ */
|
||||
static t_class *phasor_class, *scalarphasor_class;
|
||||
|
||||
#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
|
||||
|
||||
typedef struct _phasor
|
||||
{
|
||||
t_object x_obj;
|
||||
double x_phase;
|
||||
float x_conv;
|
||||
float x_f; /* scalar frequency */
|
||||
} t_phasor;
|
||||
|
||||
static void *phasor_new(t_floatarg f)
|
||||
{
|
||||
t_phasor *x = (t_phasor *)pd_new(phasor_class);
|
||||
x->x_f = f;
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
|
||||
x->x_phase = 0;
|
||||
x->x_conv = 0;
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *phasor_perform(t_int *w)
|
||||
{
|
||||
t_phasor *x = (t_phasor *)(w[1]);
|
||||
t_float *in = (t_float *)(w[2]);
|
||||
t_float *out = (t_float *)(w[3]);
|
||||
int n = (int)(w[4]);
|
||||
double dphase = x->x_phase + UNITBIT32;
|
||||
union tabfudge tf;
|
||||
int normhipart;
|
||||
float conv = x->x_conv;
|
||||
|
||||
tf.tf_d = UNITBIT32;
|
||||
normhipart = tf.tf_i[HIOFFSET];
|
||||
tf.tf_d = dphase;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
dphase += *in++ * conv;
|
||||
*out++ = tf.tf_d - UNITBIT32;
|
||||
tf.tf_d = dphase;
|
||||
}
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
x->x_phase = tf.tf_d - UNITBIT32;
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void phasor_dsp(t_phasor *x, t_signal **sp)
|
||||
{
|
||||
x->x_conv = 1./sp[0]->s_sr;
|
||||
dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void phasor_ft1(t_phasor *x, t_float f)
|
||||
{
|
||||
x->x_phase = f;
|
||||
}
|
||||
|
||||
static void phasor_setup(void)
|
||||
{
|
||||
phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
|
||||
sizeof(t_phasor), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
|
||||
class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(phasor_class, (t_method)phasor_ft1,
|
||||
gensym("ft1"), A_FLOAT, 0);
|
||||
}
|
||||
|
||||
#endif /* Hoeldrich version */
|
||||
|
||||
/* ------------------------ cos~ ----------------------------- */
|
||||
|
||||
float *cos_table;
|
||||
|
||||
static t_class *cos_class;
|
||||
|
||||
typedef struct _cos
|
||||
{
|
||||
t_object x_obj;
|
||||
float x_f;
|
||||
} t_cos;
|
||||
|
||||
static void *cos_new(void)
|
||||
{
|
||||
t_cos *x = (t_cos *)pd_new(cos_class);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *cos_perform(t_int *w)
|
||||
{
|
||||
t_float *in = (t_float *)(w[1]);
|
||||
t_float *out = (t_float *)(w[2]);
|
||||
int n = (int)(w[3]);
|
||||
float *tab = cos_table, *addr, f1, f2, frac;
|
||||
double dphase;
|
||||
int normhipart;
|
||||
union tabfudge tf;
|
||||
|
||||
tf.tf_d = UNITBIT32;
|
||||
normhipart = tf.tf_i[HIOFFSET];
|
||||
|
||||
#if 0 /* this is the readable version of the code. */
|
||||
while (n--)
|
||||
{
|
||||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
||||
tf.tf_d = dphase;
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
}
|
||||
#endif
|
||||
#if 1 /* this is the same, unwrapped by hand. */
|
||||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
||||
tf.tf_d = dphase;
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
while (--n)
|
||||
{
|
||||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
tf.tf_d = dphase;
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
}
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
#endif
|
||||
return (w+4);
|
||||
}
|
||||
|
||||
static void cos_dsp(t_cos *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void cos_maketable(void)
|
||||
{
|
||||
int i;
|
||||
float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
|
||||
union tabfudge tf;
|
||||
|
||||
if (cos_table) return;
|
||||
cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
|
||||
for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
|
||||
fp++, phase += phsinc)
|
||||
*fp = cos(phase);
|
||||
|
||||
/* here we check at startup whether the byte alignment
|
||||
is as we declared it. If not, the code has to be
|
||||
recompiled the other way. */
|
||||
tf.tf_d = UNITBIT32 + 0.5;
|
||||
if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
|
||||
bug("cos~: unexpected machine alignment");
|
||||
}
|
||||
|
||||
static void cos_setup(void)
|
||||
{
|
||||
cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
|
||||
sizeof(t_cos), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
|
||||
class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
|
||||
cos_maketable();
|
||||
}
|
||||
|
||||
/* ------------------------ osc~ ----------------------------- */
|
||||
|
||||
static t_class *osc_class, *scalarosc_class;
|
||||
|
||||
typedef struct _osc
|
||||
{
|
||||
t_object x_obj;
|
||||
double x_phase;
|
||||
float x_conv;
|
||||
float x_f; /* frequency if scalar */
|
||||
} t_osc;
|
||||
|
||||
static void *osc_new(t_floatarg f)
|
||||
{
|
||||
t_osc *x = (t_osc *)pd_new(osc_class);
|
||||
x->x_f = f;
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
|
||||
x->x_phase = 0;
|
||||
x->x_conv = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *osc_perform(t_int *w)
|
||||
{
|
||||
t_osc *x = (t_osc *)(w[1]);
|
||||
t_float *in = (t_float *)(w[2]);
|
||||
t_float *out = (t_float *)(w[3]);
|
||||
int n = (int)(w[4]);
|
||||
float *tab = cos_table, *addr, f1, f2, frac;
|
||||
double dphase = x->x_phase + UNITBIT32;
|
||||
int normhipart;
|
||||
union tabfudge tf;
|
||||
float conv = x->x_conv;
|
||||
|
||||
tf.tf_d = UNITBIT32;
|
||||
normhipart = tf.tf_i[HIOFFSET];
|
||||
#if 0
|
||||
while (n--)
|
||||
{
|
||||
tf.tf_d = dphase;
|
||||
dphase += *in++ * conv;
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
tf.tf_d = dphase;
|
||||
dphase += *in++ * conv;
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
while (--n)
|
||||
{
|
||||
tf.tf_d = dphase;
|
||||
f1 = addr[0];
|
||||
dphase += *in++ * conv;
|
||||
f2 = addr[1];
|
||||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
}
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
*out++ = f1 + frac * (f2 - f1);
|
||||
#endif
|
||||
|
||||
tf.tf_d = UNITBIT32 * COSTABSIZE;
|
||||
normhipart = tf.tf_i[HIOFFSET];
|
||||
tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
|
||||
return (w+5);
|
||||
}
|
||||
|
||||
static void osc_dsp(t_osc *x, t_signal **sp)
|
||||
{
|
||||
x->x_conv = COSTABSIZE/sp[0]->s_sr;
|
||||
dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void osc_ft1(t_osc *x, t_float f)
|
||||
{
|
||||
x->x_phase = COSTABSIZE * f;
|
||||
}
|
||||
|
||||
static void osc_setup(void)
|
||||
{
|
||||
osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
|
||||
sizeof(t_osc), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
|
||||
class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
|
||||
|
||||
cos_maketable();
|
||||
}
|
||||
|
||||
/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
|
||||
|
||||
typedef struct vcfctl
|
||||
{
|
||||
float c_re;
|
||||
float c_im;
|
||||
float c_q;
|
||||
float c_isr;
|
||||
} t_vcfctl;
|
||||
|
||||
typedef struct sigvcf
|
||||
{
|
||||
t_object x_obj;
|
||||
t_vcfctl x_cspace;
|
||||
t_vcfctl *x_ctl;
|
||||
float x_f;
|
||||
} t_sigvcf;
|
||||
|
||||
t_class *sigvcf_class;
|
||||
|
||||
static void *sigvcf_new(t_floatarg q)
|
||||
{
|
||||
t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
|
||||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
x->x_ctl = &x->x_cspace;
|
||||
x->x_cspace.c_re = 0;
|
||||
x->x_cspace.c_im = 0;
|
||||
x->x_cspace.c_q = q;
|
||||
x->x_cspace.c_isr = 0;
|
||||
x->x_f = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
|
||||
{
|
||||
x->x_ctl->c_q = (f > 0 ? f : 0.f);
|
||||
}
|
||||
|
||||
static t_int *sigvcf_perform(t_int *w)
|
||||
{
|
||||
float *in1 = (float *)(w[1]);
|
||||
float *in2 = (float *)(w[2]);
|
||||
float *out1 = (float *)(w[3]);
|
||||
float *out2 = (float *)(w[4]);
|
||||
t_vcfctl *c = (t_vcfctl *)(w[5]);
|
||||
int n = (t_int)(w[6]);
|
||||
int i;
|
||||
float re = c->c_re, re2;
|
||||
float im = c->c_im;
|
||||
float q = c->c_q;
|
||||
float qinv = (q > 0? 1.0f/q : 0);
|
||||
float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
|
||||
float isr = c->c_isr;
|
||||
float coefr, coefi;
|
||||
float *tab = cos_table, *addr, f1, f2, frac;
|
||||
double dphase;
|
||||
int normhipart, tabindex;
|
||||
union tabfudge tf;
|
||||
|
||||
tf.tf_d = UNITBIT32;
|
||||
normhipart = tf.tf_i[HIOFFSET];
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float cf, cfindx, r, oneminusr;
|
||||
cf = *in2++ * isr;
|
||||
if (cf < 0) cf = 0;
|
||||
cfindx = cf * (float)(COSTABSIZE/6.28318f);
|
||||
r = (qinv > 0 ? 1 - cf * qinv : 0);
|
||||
if (r < 0) r = 0;
|
||||
oneminusr = 1.0f - r;
|
||||
dphase = ((double)(cfindx)) + UNITBIT32;
|
||||
tf.tf_d = dphase;
|
||||
tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
|
||||
addr = tab + tabindex;
|
||||
tf.tf_i[HIOFFSET] = normhipart;
|
||||
frac = tf.tf_d - UNITBIT32;
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
coefr = r * (f1 + frac * (f2 - f1));
|
||||
|
||||
addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
|
||||
f1 = addr[0];
|
||||
f2 = addr[1];
|
||||
coefi = r * (f1 + frac * (f2 - f1));
|
||||
|
||||
f1 = *in1++;
|
||||
re2 = re;
|
||||
*out1++ = re = ampcorrect * oneminusr * f1
|
||||
+ coefr * re2 - coefi * im;
|
||||
*out2++ = im = coefi * re2 + coefr * im;
|
||||
}
|
||||
if (PD_BIGORSMALL(re))
|
||||
re = 0;
|
||||
if (PD_BIGORSMALL(im))
|
||||
im = 0;
|
||||
c->c_re = re;
|
||||
c->c_im = im;
|
||||
return (w+7);
|
||||
}
|
||||
|
||||
static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
|
||||
{
|
||||
x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
|
||||
dsp_add(sigvcf_perform, 6,
|
||||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
|
||||
x->x_ctl, sp[0]->s_n);
|
||||
|
||||
}
|
||||
|
||||
void sigvcf_setup(void)
|
||||
{
|
||||
sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
|
||||
sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
|
||||
CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
|
||||
class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
|
||||
class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
|
||||
gensym("ft1"), A_FLOAT, 0);
|
||||
}
|
||||
|
||||
/* -------------------------- noise~ ------------------------------ */
|
||||
static t_class *noise_class;
|
||||
|
||||
typedef struct _noise
|
||||
{
|
||||
t_object x_obj;
|
||||
int x_val;
|
||||
} t_noise;
|
||||
|
||||
static void *noise_new(void)
|
||||
{
|
||||
t_noise *x = (t_noise *)pd_new(noise_class);
|
||||
static int init = 307;
|
||||
x->x_val = (init *= 1319);
|
||||
outlet_new(&x->x_obj, gensym("signal"));
|
||||
return (x);
|
||||
}
|
||||
|
||||
static t_int *noise_perform(t_int *w)
|
||||
{
|
||||
t_float *out = (t_float *)(w[1]);
|
||||
int *vp = (int *)(w[2]);
|
||||
int n = (int)(w[3]);
|
||||
int val = *vp;
|
||||
while (n--)
|
||||
{
|
||||
*out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
|
||||
(float)(1.0 / 0x40000000);
|
||||
val = val * 435898247 + 382842987;
|
||||
}
|
||||
*vp = val;
|
||||
return (w+4);
|
||||
}
|
||||
|
||||
static void noise_dsp(t_noise *x, t_signal **sp)
|
||||
{
|
||||
dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
|
||||
}
|
||||
|
||||
static void noise_setup(void)
|
||||
{
|
||||
noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
|
||||
sizeof(t_noise), 0, 0);
|
||||
class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- global setup routine ---------------- */
|
||||
void d_osc_setup(void)
|
||||
{
|
||||
phasor_setup();
|
||||
cos_setup();
|
||||
osc_setup();
|
||||
sigvcf_setup();
|
||||
noise_setup();
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#N canvas 0 0 236 296 10;
|
||||
#X obj 79 77 gcanvas 80 80 0 0;
|
||||
#X floatatom 42 209 5 0 0 0 - - -;
|
||||
#X floatatom 107 205 5 0 0 0 - - -;
|
||||
#X floatatom 149 210 5 0 0 0 - - -;
|
||||
#X connect 0 0 1 0;
|
||||
#X connect 0 1 2 0;
|
||||
#X connect 0 2 3 0;
|
||||
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
PREFIX = /usr/
|
||||
EXT = pd_linux
|
||||
|
||||
# pd specific
|
||||
|
||||
VPATH = ../obj:./
|
||||
OBJ_DIR = ../obj
|
||||
BIN_DIR = ../bin
|
||||
|
||||
BROOT=/usr
|
||||
X11LIB = $(BROOT)/X11R6/lib
|
||||
|
||||
DEFINES = -DPD -DUNIX
|
||||
|
||||
pd-gui_INCLUDES = -I$(BROOT)/include/tcl8.4 -I$(BROOT)/X11R6/include
|
||||
pd-gui_LIBS = -ltk8.4 -ltcl8.4 -lX11 -ldl
|
||||
pd-gui_LDFLAGS = -L$(X11LIB)
|
||||
pd-gui_DEFINES = $(DEFINES)
|
||||
|
||||
pd_LIBS = -lm -lpthread -ldl
|
||||
pd_LDFLAGS = -Wl,-export-dynamic
|
||||
pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
|
||||
-DFIXEDPOINT -DUSEAPI_OSS -DDL_OPEN
|
||||
|
||||
extra_DEFINES = $(DEFINES) -DFIXEDPOINT
|
||||
extra_INCLUDES = -I../src
|
||||
extra_LDFLAGS = -shared
|
||||
|
||||
# IPOD toolchain
|
||||
|
||||
ifeq ($(CC), arm-elf-gcc)
|
||||
pd_LDFLAGS += -elf2flt
|
||||
pd_LIBS = -lm -lpthread
|
||||
pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
|
||||
-DFIXEDPOINT -DUSEAPI_OSS -D__linux__ -Dfork=getpid
|
||||
extra_DEFINES += -D__linux__ -Dfork=getpid
|
||||
endif
|
||||
|
||||
# BLACKFIN toolchain
|
||||
|
||||
ifeq ($(CC), bfin-uclinux-gcc)
|
||||
pd_LIBS = -lm -lpthread
|
||||
pd_DEFINES = $(DEFINES) -DINSTALL_PREFIX=\"$(PREFIX)\" \
|
||||
-DFIXEDPOINT -DUSEAPI_OSS -D__linux__
|
||||
extra_DEFINES += -D__linux__
|
||||
endif
|
||||
|
||||
# the sources
|
||||
|
||||
pd_SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
|
||||
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
|
||||
g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
|
||||
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
|
||||
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
|
||||
m_conf.c m_glob.c m_sched.c \
|
||||
s_main.c s_inter.c s_file.c s_print.c \
|
||||
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \
|
||||
d_ugen.c d_arithmetic.c d_dac.c d_misc.c \
|
||||
d_fft.c d_mayer_fft.c d_fftroutine.c d_global.c \
|
||||
d_resample.c d_ctl.c d_soundfile.c \
|
||||
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
|
||||
x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c \
|
||||
s_midi_oss.c s_audio_oss.c
|
||||
|
||||
pd_SRC += d_imayer_fft.c m_fixed.c
|
||||
|
||||
pd_OBJ = $(pd_SRC:.c=.o)
|
||||
|
||||
pd-gui_SRC = t_main.c t_tkcmd.c
|
||||
pd-gui_OBJ = $(pd-gui_SRC:.c=.o)
|
||||
|
||||
extra_SRC = $(shell ls ../intern/*.c) $(shell ls ../extra/*.c)
|
||||
extra_OBJ = $(extra_SRC:.c=.o)
|
||||
extra_EXT = $(extra_SRC:.c=.pd_linux)
|
||||
|
||||
#
|
||||
# ------------------ targets ------------------------------------
|
||||
#
|
||||
|
||||
all: $(BIN_DIR)/pd \
|
||||
$(BIN_DIR)/pd-gui \
|
||||
$(BIN_DIR)/pd-watchdog \
|
||||
$(BIN_DIR)/pdsend \
|
||||
$(BIN_DIR)/pdreceive \
|
||||
$(BIN_DIR)/pd.tk \
|
||||
extra
|
||||
|
||||
pd: $(BIN_DIR)/pd
|
||||
pd-gui: $(BIN_DIR)/pd-gui
|
||||
pd-watchdog: $(BIN_DIR)/pd-watchdog
|
||||
|
||||
static:
|
||||
make pd_SRC="$(pd_SRC) $(extra_SRC)" DEFINES="-DPD -DUNIX -DSTATIC" \
|
||||
pd pd-gui pd-watchdog $(BIN_DIR)/pdsend \
|
||||
$(BIN_DIR)/pdreceive $(BIN_DIR)/pd.tk
|
||||
|
||||
extra: $(extra_EXT)
|
||||
|
||||
ipod:
|
||||
make CC=arm-elf-gcc static
|
||||
|
||||
blackfin:
|
||||
make CC=bfin-uclinux-gcc static
|
||||
|
||||
$(pd_OBJ) : %.o : %.c
|
||||
$(CC) $(CFLAGS) $(pd_DEFINES) $(pd_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
|
||||
|
||||
$(pd-gui_OBJ) : %.o : %.c
|
||||
$(CC) $(CFLAGS) $(pd-gui_DEFINES) $(pd-gui_INCLUDES) -c -o $(OBJ_DIR)/$@ $+
|
||||
|
||||
$(extra_OBJ) : %.o : %.c
|
||||
$(CC) $(CFLAGS) $(extra_DEFINES) $(extra_INCLUDES) -c -o $@ $*.c
|
||||
|
||||
$(extra_EXT) : %.$(EXT) : %.o
|
||||
$(CC) -o $@ $(extra_LDFLAGS) $+
|
||||
|
||||
$(BIN_DIR)/pd-watchdog: s_watchdog.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -o $@ s_watchdog.c
|
||||
|
||||
$(BIN_DIR)/pdsend: u_pdsend.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdsend.c
|
||||
|
||||
$(BIN_DIR)/pdreceive: u_pdreceive.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -o $@ u_pdreceive.c
|
||||
|
||||
$(BIN_DIR)/pd: $(pd_OBJ)
|
||||
cd ../obj; $(CC) $(pd_LDFLAGS) -o $@ $(pd_OBJ) $(pd_LIBS)
|
||||
|
||||
$(BIN_DIR)/pd-gui: $(pd-gui_OBJ)
|
||||
cd ../obj; $(CC) -o $@ $(pd-gui_OBJ) $(pd-gui_LDFLAGS) $(pd-gui_LIBS)
|
||||
|
||||
$(BIN_DIR)/pd.tk: u_main.tk
|
||||
echo set pd_nt 0 > $(BIN_DIR)/pd.tk
|
||||
grep -v "set pd_nt" < u_main.tk >> $@
|
||||
|
||||
INSTDIR = $(DESTDIR)/$(PREFIX)
|
||||
|
||||
install: all
|
||||
# Create the directory structure
|
||||
|
||||
install -d $(INSTDIR)/lib/pd/bin
|
||||
install -d $(INSTDIR)/lib/pd/extra
|
||||
install -d $(INSTDIR)/lib/pd/intern
|
||||
install -d $(INSTDIR)/lib/pd/doc
|
||||
install -d $(INSTDIR)/bin
|
||||
install -d $(INSTDIR)/include
|
||||
|
||||
install $(BIN_DIR)/pd-gui $(INSTDIR)/lib/pd/bin/
|
||||
install $(BIN_DIR)/pd-watchdog $(INSTDIR)/lib/pd/bin/
|
||||
install -m 644 $(BIN_DIR)/pd.tk $(INSTDIR)/lib/pd/bin/
|
||||
install -m 755 $(BIN_DIR)/pd $(INSTDIR)/bin/
|
||||
install -m 755 $(BIN_DIR)/pdsend $(INSTDIR)/bin/pdsend
|
||||
install -m 755 $(BIN_DIR)/pdreceive $(INSTDIR)/bin/pdreceive
|
||||
cp -r ../doc/7.stuff $(INSTDIR)/lib/pd/doc
|
||||
cp -r ../doc/5.reference $(INSTDIR)/lib/pd/doc
|
||||
install -m 644 m_pd.h $(INSTDIR)/include/m_pd.h
|
||||
|
||||
# Install the externals if possible
|
||||
cp ../extra/*.pd_linux $(INSTDIR)/lib/pd/extra
|
||||
cp ../intern/*.pd_linux $(INSTDIR)/lib/pd/intern
|
||||
|
||||
# Install the ICON and desktop file
|
||||
install -d $(INSTDIR)/share/pixmaps
|
||||
install -d $(INSTDIR)/share/applications
|
||||
cp ../ipkg/pd-icon.png $(INSTDIR)/share/pixmaps
|
||||
cp ../ipkg/pd.desktop $(INSTDIR)/share/applications/
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f `find ../extra/ -name "*.pd_*"`
|
||||
-rm -f tags
|
||||
-rm -f ../obj/* $(BIN_DIR)/* ../extra/*.{o,$(EXT)} ../intern/*.{o,$(EXT)}
|
||||
-rm -f *~
|
||||
-rm -f $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive
|
||||
|
||||
|
|
@ -1,946 +0,0 @@
|
|||
/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
|
||||
* Winfried Ritsch, Karl MacMillan, and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* this file inputs and outputs audio using the ALSA API available on linux. */
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
typedef int16_t t_alsa_sample16;
|
||||
typedef int32_t t_alsa_sample32;
|
||||
#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
|
||||
#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
|
||||
#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE)
|
||||
#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE)
|
||||
#define ALSA_MAXDEV 1
|
||||
#define ALSA_JITTER 1024
|
||||
#define ALSA_EXTRABUFFER 2048
|
||||
#define ALSA_DEFFRAGSIZE 64
|
||||
#define ALSA_DEFNFRAG 12
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX 0x7fffffff
|
||||
#endif
|
||||
|
||||
#if (SND_LIB_MAJOR < 1)
|
||||
#define ALSAAPI9
|
||||
#endif
|
||||
|
||||
typedef struct _alsa_dev
|
||||
{
|
||||
snd_pcm_t *inhandle;
|
||||
snd_pcm_t *outhandle;
|
||||
int innoninterleave; /* true if we're set for noninterleaved read */
|
||||
int outnoninterleave; /* same for write */
|
||||
} t_alsa_dev;
|
||||
|
||||
t_alsa_dev alsa_device;
|
||||
static void *alsa_snd_buf = 0;
|
||||
static void **alsa_buf_ptrs;
|
||||
static int alsa_samplewidth;
|
||||
static snd_pcm_status_t* in_status;
|
||||
static snd_pcm_status_t* out_status;
|
||||
|
||||
static int alsa_mode;
|
||||
static int alsa_buf_samps; /* believed actual ALSA bufsize in sample frames */
|
||||
static int alsa_inchannels;
|
||||
static int alsa_outchannels;
|
||||
|
||||
/* Defines */
|
||||
#define DEBUG(x) x
|
||||
#define DEBUG2(x) {x;}
|
||||
|
||||
static void alsa_checkiosync( void);
|
||||
static void alsa_numbertoname(int devno, char *devname, int nchar);
|
||||
|
||||
/* don't assume we can turn all 31 bits when doing float-to-fix;
|
||||
otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
|
||||
#define FMAX 0x7ffff000
|
||||
#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
|
||||
|
||||
/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
|
||||
|
||||
static void check_error(int err, const char *why)
|
||||
{
|
||||
if (err < 0)
|
||||
fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
|
||||
}
|
||||
|
||||
/* was: alsa_open_audio(int wantinchans, int wantoutchans, int srate) */
|
||||
|
||||
int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
|
||||
int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
|
||||
int *choutdev, int rate)
|
||||
{
|
||||
int err, inchans = 0, outchans = 0, subunitdir;
|
||||
char devname[512];
|
||||
snd_pcm_hw_params_t* hw_params;
|
||||
snd_pcm_sw_params_t* sw_params;
|
||||
snd_output_t* out;
|
||||
int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
|
||||
int nfrags, i;
|
||||
short* tmp_buf;
|
||||
unsigned int tmp_uint;
|
||||
snd_pcm_uframes_t tmp_snd_pcm_uframes;
|
||||
int wantinchans, wantoutchans, devno;
|
||||
|
||||
if (naudioindev >= 2 || naudiooutdev >= 2)
|
||||
post("alsa: only one input and output device allowed (extras ignored");
|
||||
if (naudioindev >= 1 && naudiooutdev >= 1 &&
|
||||
audioindev[0] != audiooutdev[0])
|
||||
post("alsa: changing output device to agree with input device");
|
||||
if (nchindev)
|
||||
wantinchans = chindev[0];
|
||||
else wantinchans = (naudioindev ? 2 : 0);
|
||||
if (nchoutdev)
|
||||
wantoutchans = choutdev[0];
|
||||
else wantoutchans = (naudiooutdev ? 2 : 0);
|
||||
devno = (naudioindev > 0 ? audioindev[0] :
|
||||
(naudiooutdev > 0 ? audiooutdev[0] : 0));
|
||||
|
||||
alsa_numbertoname(devno, devname, 512);
|
||||
|
||||
if (sys_verbose)
|
||||
post("device name %s; channels in %d, out %d", devname, wantinchans,
|
||||
wantoutchans);
|
||||
|
||||
nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size);
|
||||
/* save our belief as to ALSA's buffer size for later */
|
||||
alsa_buf_samps = nfrags * frag_size;
|
||||
|
||||
if (sys_verbose)
|
||||
post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
|
||||
|
||||
alsa_device.innoninterleave = alsa_device.outnoninterleave = 0;
|
||||
if (wantinchans)
|
||||
{
|
||||
err = snd_pcm_open(&alsa_device.inhandle, devname,
|
||||
SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
||||
|
||||
check_error(err, "snd_pcm_open (input)");
|
||||
if (err < 0)
|
||||
inchans = 0;
|
||||
else
|
||||
{
|
||||
inchans = wantinchans;
|
||||
snd_pcm_nonblock(alsa_device.inhandle, 1);
|
||||
}
|
||||
}
|
||||
if (wantoutchans)
|
||||
{
|
||||
err = snd_pcm_open(&alsa_device.outhandle, devname,
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
|
||||
check_error(err, "snd_pcm_open (output)");
|
||||
if (err < 0)
|
||||
outchans = 0;
|
||||
else
|
||||
{
|
||||
outchans = wantoutchans;
|
||||
snd_pcm_nonblock(alsa_device.outhandle, 1);
|
||||
}
|
||||
}
|
||||
if (inchans)
|
||||
{
|
||||
if (sys_verbose)
|
||||
post("opening sound input...");
|
||||
err = snd_pcm_hw_params_malloc(&hw_params);
|
||||
check_error(err, "snd_pcm_hw_params_malloc (input)");
|
||||
|
||||
// get the default params
|
||||
err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
|
||||
check_error(err, "snd_pcm_hw_params_any (input)");
|
||||
|
||||
/* try to set interleaved access */
|
||||
err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
|
||||
hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (err < 0)
|
||||
{
|
||||
/* OK, so try non-interleaved */
|
||||
err = snd_pcm_hw_params_set_access(alsa_device.inhandle,
|
||||
hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
|
||||
if (err >= 0)
|
||||
{
|
||||
post("using non-interleaved audio input");
|
||||
alsa_device.innoninterleave = 1;
|
||||
}
|
||||
}
|
||||
check_error(err, "snd_pcm_hw_params_set_access (input)");
|
||||
// Try to set 32 bit format first
|
||||
err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
|
||||
SND_PCM_FORMAT_S32);
|
||||
if (err < 0)
|
||||
{
|
||||
/* fprintf(stderr,
|
||||
"PD-ALSA: 32 bit format not available - using 16\n"); */
|
||||
err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
|
||||
SND_PCM_FORMAT_S16);
|
||||
check_error(err, "snd_pcm_hw_params_set_format (input)");
|
||||
alsa_samplewidth = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
alsa_samplewidth = 4;
|
||||
}
|
||||
post("Sample width set to %d bytes", alsa_samplewidth);
|
||||
// set the subformat
|
||||
err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
|
||||
SND_PCM_SUBFORMAT_STD);
|
||||
check_error(err, "snd_pcm_hw_params_set_subformat (input)");
|
||||
// set the number of channels
|
||||
tmp_uint = inchans;
|
||||
err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
|
||||
hw_params, &tmp_uint);
|
||||
check_error(err, "snd_pcm_hw_params_set_channels (input)");
|
||||
if (tmp_uint != (unsigned)inchans)
|
||||
post("ALSA: set input channels to %d", tmp_uint);
|
||||
inchans = tmp_uint;
|
||||
// set the sampling rate
|
||||
err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
|
||||
&rate, 0);
|
||||
check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
|
||||
#if 0
|
||||
err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
|
||||
post("input sample rate %d", err);
|
||||
#endif
|
||||
// set the period - ie frag size
|
||||
// post("fragsize a %d", frag_size);
|
||||
|
||||
/* LATER try this to get a recommended period size...
|
||||
right now, it trips an assertion failure in ALSA lib */
|
||||
#if 0
|
||||
post("input period was %d, min %d, max %d\n",
|
||||
snd_pcm_hw_params_get_period_size(hw_params, 0),
|
||||
snd_pcm_hw_params_get_period_size_min(hw_params, 0),
|
||||
snd_pcm_hw_params_get_period_size_max(hw_params, 0));
|
||||
#endif
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
|
||||
hw_params,
|
||||
(snd_pcm_uframes_t)
|
||||
frag_size, 0);
|
||||
#else
|
||||
tmp_snd_pcm_uframes = frag_size;
|
||||
err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
|
||||
hw_params, &tmp_snd_pcm_uframes, 0);
|
||||
#endif
|
||||
check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
|
||||
// post("fragsize b %d", frag_size);
|
||||
// set the number of periods - ie numfrags
|
||||
// post("nfrags a %d", nfrags);
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
|
||||
hw_params, nfrags, 0);
|
||||
#else
|
||||
tmp_uint = nfrags;
|
||||
err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
|
||||
hw_params, &tmp_uint, 0);
|
||||
#endif
|
||||
check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
|
||||
// set the buffer size
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
|
||||
hw_params, nfrags * frag_size);
|
||||
#else
|
||||
tmp_snd_pcm_uframes = nfrags * frag_size;
|
||||
err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
|
||||
hw_params, &tmp_snd_pcm_uframes);
|
||||
#endif
|
||||
check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
|
||||
|
||||
err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
|
||||
check_error(err, "snd_pcm_hw_params (input)");
|
||||
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
err = snd_pcm_sw_params_malloc(&sw_params);
|
||||
check_error(err, "snd_pcm_sw_params_malloc (input)");
|
||||
err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
|
||||
check_error(err, "snd_pcm_sw_params_current (input)");
|
||||
err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
|
||||
sw_params, nfrags * frag_size);
|
||||
check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
|
||||
err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
|
||||
sw_params, 0x7fffffff);
|
||||
check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
|
||||
err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
|
||||
frag_size);
|
||||
check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
|
||||
err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
|
||||
check_error(err, "snd_pcm_sw_params (input)");
|
||||
|
||||
snd_pcm_sw_params_free(sw_params);
|
||||
|
||||
snd_output_stdio_attach(&out, stderr, 0);
|
||||
#if 0
|
||||
if (sys_verbose)
|
||||
{
|
||||
snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
|
||||
snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (outchans)
|
||||
{
|
||||
int foo;
|
||||
if (sys_verbose)
|
||||
post("opening sound output...");
|
||||
err = snd_pcm_hw_params_malloc(&hw_params);
|
||||
check_error(err, "snd_pcm_sw_params (output)");
|
||||
|
||||
// get the default params
|
||||
err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
|
||||
check_error(err, "snd_pcm_hw_params_any (output)");
|
||||
// set interleaved access - FIXME deal with other access types
|
||||
err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
check_error(err, "snd_pcm_hw_params_set_access (output)");
|
||||
|
||||
/* try to set interleaved access */
|
||||
err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
|
||||
hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (err < 0)
|
||||
{
|
||||
/* OK, so try non-interleaved */
|
||||
err = snd_pcm_hw_params_set_access(alsa_device.outhandle,
|
||||
hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
|
||||
if (err >= 0)
|
||||
{
|
||||
post("using non-interleaved audio");
|
||||
alsa_device.outnoninterleave = 1;
|
||||
}
|
||||
}
|
||||
check_error(err, "snd_pcm_hw_params_set_access (output)");
|
||||
|
||||
|
||||
// Try to set 32 bit format first
|
||||
err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
|
||||
SND_PCM_FORMAT_S32);
|
||||
if (err < 0)
|
||||
{
|
||||
err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
|
||||
hw_params,SND_PCM_FORMAT_S16);
|
||||
check_error(err, "snd_pcm_hw_params_set_format (output)");
|
||||
/* fprintf(stderr,
|
||||
"PD-ALSA: 32 bit format not available - using 16\n"); */
|
||||
alsa_samplewidth = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
alsa_samplewidth = 4;
|
||||
}
|
||||
// set the subformat
|
||||
err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
|
||||
SND_PCM_SUBFORMAT_STD);
|
||||
check_error(err, "snd_pcm_hw_params_set_subformat (output)");
|
||||
// set the number of channels
|
||||
tmp_uint = outchans;
|
||||
err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
|
||||
hw_params, &tmp_uint);
|
||||
check_error(err, "snd_pcm_hw_params_set_channels (output)");
|
||||
if (tmp_uint != (unsigned)outchans)
|
||||
post("alsa: set output channels to %d", tmp_uint);
|
||||
outchans = tmp_uint;
|
||||
// set the sampling rate
|
||||
err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
|
||||
&rate, 0);
|
||||
check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
|
||||
#if 0
|
||||
err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
|
||||
post("output sample rate %d", err);
|
||||
#endif
|
||||
// set the period - ie frag size
|
||||
#if 0
|
||||
post("output period was %d, min %d, max %d\n",
|
||||
snd_pcm_hw_params_get_period_size(hw_params, 0),
|
||||
snd_pcm_hw_params_get_period_size_min(hw_params, 0),
|
||||
snd_pcm_hw_params_get_period_size_max(hw_params, 0));
|
||||
#endif
|
||||
// post("fragsize c %d", frag_size);
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
|
||||
hw_params,
|
||||
(snd_pcm_uframes_t)
|
||||
frag_size, 0);
|
||||
#else
|
||||
tmp_snd_pcm_uframes = frag_size;
|
||||
err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
|
||||
hw_params, &tmp_snd_pcm_uframes, 0);
|
||||
#endif
|
||||
// post("fragsize d %d", frag_size);
|
||||
check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
|
||||
// set the number of periods - ie numfrags
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
|
||||
hw_params, nfrags, 0);
|
||||
#else
|
||||
tmp_uint = nfrags;
|
||||
err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
|
||||
hw_params, &tmp_uint, 0);
|
||||
#endif
|
||||
check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
|
||||
// set the buffer size
|
||||
#ifdef ALSAAPI9
|
||||
err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
|
||||
hw_params, nfrags * frag_size);
|
||||
#else
|
||||
tmp_snd_pcm_uframes = nfrags * frag_size;
|
||||
err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
|
||||
hw_params, &tmp_snd_pcm_uframes);
|
||||
#endif
|
||||
check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
|
||||
|
||||
err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
|
||||
check_error(err, "snd_pcm_hw_params (output)");
|
||||
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
err = snd_pcm_sw_params_malloc(&sw_params);
|
||||
check_error(err, "snd_pcm_sw_params_malloc (output)");
|
||||
err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
|
||||
check_error(err, "snd_pcm_sw_params_current (output)");
|
||||
err = snd_pcm_sw_params_set_start_threshold(alsa_device.outhandle,
|
||||
sw_params, nfrags * frag_size);
|
||||
check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
|
||||
err = snd_pcm_sw_params_set_stop_threshold(alsa_device.outhandle,
|
||||
sw_params, 0x7fffffff);
|
||||
check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
|
||||
err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
|
||||
frag_size);
|
||||
check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
|
||||
err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
|
||||
check_error(err, "snd_pcm_sw_params (output)");
|
||||
snd_pcm_sw_params_free(sw_params);
|
||||
|
||||
snd_output_stdio_attach(&out, stderr, 0);
|
||||
#if 0
|
||||
if (sys_verbose)
|
||||
{
|
||||
snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
|
||||
snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (inchans)
|
||||
snd_pcm_prepare(alsa_device.inhandle);
|
||||
if (outchans)
|
||||
snd_pcm_prepare(alsa_device.outhandle);
|
||||
|
||||
// if duplex we can link the channels so they start together
|
||||
if (inchans && outchans)
|
||||
snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
|
||||
|
||||
// set up the status variables
|
||||
err = snd_pcm_status_malloc(&in_status);
|
||||
check_error(err, "snd_pcm_status_malloc");
|
||||
err = snd_pcm_status_malloc(&out_status);
|
||||
check_error(err, "snd_pcm_status_malloc");
|
||||
|
||||
// set up the buffer
|
||||
if (alsa_snd_buf)
|
||||
free(alsa_snd_buf);
|
||||
alsa_snd_buf = (void *)malloc(
|
||||
sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
|
||||
(outchans > inchans ? outchans : inchans));
|
||||
memset(alsa_snd_buf, 0, sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE *
|
||||
(outchans > inchans ? outchans : inchans));
|
||||
/* make an array of pointers too in case we need them */
|
||||
if (alsa_buf_ptrs)
|
||||
free(alsa_buf_ptrs);
|
||||
alsa_buf_ptrs = (void **)malloc(
|
||||
sizeof(void *) * (outchans > inchans ? outchans : inchans));
|
||||
for (i = 0; i < (outchans > inchans ? outchans : inchans); i++)
|
||||
alsa_buf_ptrs[i] = (t_alsa_sample32 *)alsa_snd_buf + i * DEFDACBLKSIZE;
|
||||
|
||||
// fill the buffer with silence
|
||||
if (outchans)
|
||||
{
|
||||
i = (frag_size * nfrags)/DEFDACBLKSIZE + 1;
|
||||
while (i--)
|
||||
{
|
||||
if (alsa_device.outnoninterleave)
|
||||
snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
|
||||
DEFDACBLKSIZE);
|
||||
else snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
|
||||
DEFDACBLKSIZE);
|
||||
}
|
||||
/* confused about this: */
|
||||
/* if ((err = snd_pcm_start(alsa_device.outhandle) < 0))
|
||||
check_error(err, "output start failed\n"); */
|
||||
}
|
||||
else if (inchans)
|
||||
{
|
||||
if (snd_pcm_start(alsa_device.inhandle) < 0)
|
||||
check_error(err, "input start failed\n");
|
||||
}
|
||||
alsa_outchannels = outchans;
|
||||
alsa_inchannels = inchans;
|
||||
|
||||
return (!(inchans || outchans));
|
||||
}
|
||||
|
||||
void alsa_close_audio(void)
|
||||
{
|
||||
int err;
|
||||
if (alsa_inchannels)
|
||||
{
|
||||
err = snd_pcm_close(alsa_device.inhandle);
|
||||
check_error(err, "snd_pcm_close (input)");
|
||||
}
|
||||
if (alsa_outchannels)
|
||||
{
|
||||
err = snd_pcm_close(alsa_device.outhandle);
|
||||
check_error(err, "snd_pcm_close (output)");
|
||||
}
|
||||
}
|
||||
|
||||
// #define DEBUG_ALSA_XFER
|
||||
|
||||
int alsa_send_dacs(void)
|
||||
{
|
||||
static int16_t *sp;
|
||||
static int xferno = 0;
|
||||
static int callno = 0;
|
||||
static double timenow;
|
||||
double timelast;
|
||||
t_sample *fp, *fp1, *fp2;
|
||||
int i, j, k, err, devno = 0;
|
||||
int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
|
||||
int result;
|
||||
int inchannels = (sys_inchannels > alsa_inchannels ?
|
||||
alsa_inchannels : sys_inchannels);
|
||||
int outchannels = (sys_outchannels > alsa_outchannels ?
|
||||
alsa_outchannels : sys_outchannels);
|
||||
unsigned int intransfersize = DEFDACBLKSIZE;
|
||||
unsigned int outtransfersize = DEFDACBLKSIZE;
|
||||
|
||||
// get the status
|
||||
if (!inchannels && !outchannels)
|
||||
{
|
||||
return SENDDACS_NO;
|
||||
}
|
||||
|
||||
timelast = timenow;
|
||||
timenow = sys_getrealtime();
|
||||
|
||||
#ifdef DEBUG_ALSA_XFER
|
||||
if (timenow - timelast > 0.050)
|
||||
fprintf(stderr, "(%d)",
|
||||
(int)(1000 * (timenow - timelast))), fflush(stderr);
|
||||
#endif
|
||||
|
||||
callno++;
|
||||
|
||||
alsa_checkiosync(); /* check I/O are in sync and data not late */
|
||||
|
||||
if (alsa_inchannels)
|
||||
{
|
||||
snd_pcm_status(alsa_device.inhandle, in_status);
|
||||
if (snd_pcm_status_get_avail(in_status) < intransfersize)
|
||||
return SENDDACS_NO;
|
||||
}
|
||||
if (alsa_outchannels)
|
||||
{
|
||||
snd_pcm_status(alsa_device.outhandle, out_status);
|
||||
if (snd_pcm_status_get_avail(out_status) < outtransfersize)
|
||||
return SENDDACS_NO;
|
||||
}
|
||||
|
||||
/* do output */
|
||||
if (alsa_outchannels)
|
||||
{
|
||||
fp = sys_soundout;
|
||||
if (alsa_samplewidth == 4)
|
||||
{
|
||||
if (alsa_device.outnoninterleave)
|
||||
{
|
||||
int n = outchannels * DEFDACBLKSIZE;
|
||||
for (i = 0, fp1 = fp; i < n; i++)
|
||||
{
|
||||
float s1 = *fp1 * INT32_MAX;
|
||||
((t_alsa_sample32 *)alsa_snd_buf)[i] = CLIP32(s1);
|
||||
}
|
||||
n = alsa_outchannels * DEFDACBLKSIZE;
|
||||
for (; i < n; i++)
|
||||
((t_alsa_sample32 *)alsa_snd_buf)[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, fp1 = fp; i < outchannels; i++,
|
||||
fp1 += DEFDACBLKSIZE)
|
||||
{
|
||||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
|
||||
j += alsa_outchannels, fp2++)
|
||||
{
|
||||
float s1 = *fp2 * INT32_MAX;
|
||||
((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE)
|
||||
{
|
||||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
|
||||
j += alsa_outchannels, fp2++)
|
||||
{
|
||||
int s = *fp2 * 32767.;
|
||||
if (s > 32767)
|
||||
s = 32767;
|
||||
else if (s < -32767)
|
||||
s = -32767;
|
||||
((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alsa_device.outnoninterleave)
|
||||
result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
|
||||
outtransfersize);
|
||||
else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
|
||||
outtransfersize);
|
||||
|
||||
if (result != (int)outtransfersize)
|
||||
{
|
||||
#ifdef DEBUG_ALSA_XFER
|
||||
if (result >= 0 || errno == EAGAIN)
|
||||
fprintf(stderr, "ALSA: write returned %d of %d\n",
|
||||
result, outtransfersize);
|
||||
else fprintf(stderr, "ALSA: write: %s\n",
|
||||
snd_strerror(errno));
|
||||
fprintf(stderr,
|
||||
"inputcount %d, outputcount %d, outbufsize %d\n",
|
||||
inputcount, outputcount,
|
||||
(ALSA_EXTRABUFFER + sys_advance_samples)
|
||||
* alsa_samplewidth * outchannels);
|
||||
#endif
|
||||
sys_log_error(ERR_DACSLEPT);
|
||||
return (SENDDACS_NO);
|
||||
}
|
||||
|
||||
/* zero out the output buffer */
|
||||
memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) *
|
||||
sys_outchannels);
|
||||
if (sys_getrealtime() - timenow > 0.002)
|
||||
{
|
||||
#ifdef DEBUG_ALSA_XFER
|
||||
fprintf(stderr, "output %d took %d msec\n",
|
||||
callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
|
||||
#endif
|
||||
timenow = sys_getrealtime();
|
||||
sys_log_error(ERR_DACSLEPT);
|
||||
}
|
||||
}
|
||||
/* do input */
|
||||
if (alsa_inchannels)
|
||||
{
|
||||
if (alsa_device.innoninterleave)
|
||||
result = snd_pcm_readn(alsa_device.inhandle, alsa_buf_ptrs,
|
||||
intransfersize);
|
||||
else result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
|
||||
intransfersize);
|
||||
if (result < (int)intransfersize)
|
||||
{
|
||||
#ifdef DEBUG_ALSA_XFER
|
||||
if (result < 0)
|
||||
fprintf(stderr,
|
||||
"snd_pcm_read %d %d: %s\n",
|
||||
callno, xferno, snd_strerror(errno));
|
||||
else fprintf(stderr,
|
||||
"snd_pcm_read %d %d returned only %d\n",
|
||||
callno, xferno, result);
|
||||
fprintf(stderr,
|
||||
"inputcount %d, outputcount %d, inbufsize %d\n",
|
||||
inputcount, outputcount,
|
||||
(ALSA_EXTRABUFFER + sys_advance_samples)
|
||||
* alsa_samplewidth * inchannels);
|
||||
#endif
|
||||
sys_log_error(ERR_ADCSLEPT);
|
||||
return (SENDDACS_NO);
|
||||
}
|
||||
fp = sys_soundin;
|
||||
if (alsa_samplewidth == 4)
|
||||
{
|
||||
if (alsa_device.innoninterleave)
|
||||
{
|
||||
int n = inchannels * DEFDACBLKSIZE;
|
||||
for (i = 0, fp1 = fp; i < n; i++)
|
||||
*fp1 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[i]
|
||||
* (1./ INT32_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, fp1 = fp; i < inchannels;
|
||||
i++, fp1 += DEFDACBLKSIZE)
|
||||
{
|
||||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
|
||||
j += alsa_inchannels, fp2++)
|
||||
*fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j]
|
||||
* (1./ INT32_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE)
|
||||
{
|
||||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
|
||||
j += alsa_inchannels, fp2++)
|
||||
*fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j]
|
||||
* 3.051850e-05;
|
||||
}
|
||||
}
|
||||
}
|
||||
xferno++;
|
||||
if (sys_getrealtime() - timenow > 0.002)
|
||||
{
|
||||
#ifdef DEBUG_ALSA_XFER
|
||||
fprintf(stderr, "routine took %d msec\n",
|
||||
(int)(1000 * (sys_getrealtime() - timenow)));
|
||||
#endif
|
||||
sys_log_error(ERR_ADCSLEPT);
|
||||
}
|
||||
return SENDDACS_YES;
|
||||
}
|
||||
|
||||
void alsa_printstate( void)
|
||||
{
|
||||
int i, result;
|
||||
snd_pcm_sframes_t indelay, outdelay;
|
||||
if (sys_audioapi != API_ALSA)
|
||||
{
|
||||
error("restart-audio: implemented for ALSA only.");
|
||||
return;
|
||||
}
|
||||
if (sys_inchannels)
|
||||
{
|
||||
result = snd_pcm_delay(alsa_device.inhandle, &indelay);
|
||||
if (result < 0)
|
||||
post("snd_pcm_delay 1 failed");
|
||||
else post("in delay %d", indelay);
|
||||
}
|
||||
if (sys_outchannels)
|
||||
{
|
||||
result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
|
||||
if (result < 0)
|
||||
post("snd_pcm_delay 2 failed");
|
||||
else post("out delay %d", outdelay);
|
||||
}
|
||||
post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64);
|
||||
|
||||
post("buf samples %d", alsa_buf_samps);
|
||||
}
|
||||
|
||||
|
||||
void alsa_resync( void)
|
||||
{
|
||||
int i, result;
|
||||
if (sys_audioapi != API_ALSA)
|
||||
{
|
||||
error("restart-audio: implemented for ALSA only.");
|
||||
return;
|
||||
}
|
||||
memset(alsa_snd_buf, 0,
|
||||
sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * sys_outchannels);
|
||||
for (i = 0; i < 1000000; i++)
|
||||
{
|
||||
if (alsa_device.outnoninterleave)
|
||||
result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
|
||||
DEFDACBLKSIZE);
|
||||
else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
|
||||
DEFDACBLKSIZE);
|
||||
if (result != (int)DEFDACBLKSIZE)
|
||||
break;
|
||||
}
|
||||
post("%d written", i);
|
||||
}
|
||||
|
||||
void alsa_putzeros(int n)
|
||||
{
|
||||
int i, result;
|
||||
memset(alsa_snd_buf, 0,
|
||||
sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * alsa_outchannels);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (alsa_device.outnoninterleave)
|
||||
result = snd_pcm_writen(alsa_device.outhandle, alsa_buf_ptrs,
|
||||
DEFDACBLKSIZE);
|
||||
else result = snd_pcm_writei(alsa_device.outhandle, alsa_snd_buf,
|
||||
DEFDACBLKSIZE);
|
||||
#if 0
|
||||
if (result != DEFDACBLKSIZE)
|
||||
post("result %d", result);
|
||||
#endif
|
||||
}
|
||||
/* post ("putzeros %d", n); */
|
||||
}
|
||||
|
||||
void alsa_getzeros(int n)
|
||||
{
|
||||
int i, result;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
result = snd_pcm_readi(alsa_device.inhandle, alsa_snd_buf,
|
||||
DEFDACBLKSIZE);
|
||||
#if 0
|
||||
if (result != DEFDACBLKSIZE)
|
||||
post("result %d", result);
|
||||
#endif
|
||||
}
|
||||
/* post ("getzeros %d", n); */
|
||||
}
|
||||
|
||||
/* call this only if both input and output are open */
|
||||
static void alsa_checkiosync( void)
|
||||
{
|
||||
int i, result, checkit = 1, giveup = 1000, alreadylogged = 0;
|
||||
snd_pcm_sframes_t indelay, outdelay, defect;
|
||||
|
||||
if (!(alsa_outchannels && alsa_inchannels))
|
||||
return;
|
||||
while (checkit)
|
||||
{
|
||||
checkit = 0;
|
||||
if (giveup-- <= 0)
|
||||
return;
|
||||
result = snd_pcm_delay(alsa_device.outhandle, &outdelay);
|
||||
if (result < 0)
|
||||
{
|
||||
post("output snd_pcm_delay failed: %s", snd_strerror(result));
|
||||
if (snd_pcm_status(alsa_device.outhandle, out_status) < 0)
|
||||
post("output snd_pcm_status failed");
|
||||
else post("astate %d",
|
||||
snd_pcm_status_get_state(out_status));
|
||||
return;
|
||||
}
|
||||
if (outdelay < 0)
|
||||
sys_log_error(ERR_DATALATE), alreadylogged = 1;
|
||||
|
||||
if (sys_inchannels)
|
||||
{
|
||||
result = snd_pcm_delay(alsa_device.inhandle, &indelay);
|
||||
if (result < 0)
|
||||
{
|
||||
post("input snd_pcm_delay failed");
|
||||
return;
|
||||
}
|
||||
defect = indelay + outdelay - alsa_buf_samps;
|
||||
if (defect < -(3 * DEFDACBLKSIZE / 2) )
|
||||
{
|
||||
checkit = 1;
|
||||
alsa_putzeros(1);
|
||||
if (!alreadylogged)
|
||||
sys_log_error(ERR_RESYNC), alreadylogged = 1;
|
||||
}
|
||||
else if (defect > 0)
|
||||
{
|
||||
checkit = 1;
|
||||
alsa_getzeros(1);
|
||||
if (!alreadylogged)
|
||||
sys_log_error(ERR_RESYNC), alreadylogged = 1;
|
||||
}
|
||||
/* if (alreadylogged)
|
||||
post("in %d out %d defect %d", indelay, outdelay, defect); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int alsa_nnames = 0;
|
||||
static char **alsa_names = 0;
|
||||
|
||||
void alsa_adddev(char *name)
|
||||
{
|
||||
if (alsa_nnames)
|
||||
alsa_names = (char **)t_resizebytes(alsa_names,
|
||||
alsa_nnames * sizeof(char *),
|
||||
(alsa_nnames+1) * sizeof(char *));
|
||||
else alsa_names = (char **)t_getbytes(sizeof(char *));
|
||||
alsa_names[alsa_nnames] = gensym(name)->s_name;
|
||||
alsa_nnames++;
|
||||
}
|
||||
|
||||
static void alsa_numbertoname(int devno, char *devname, int nchar)
|
||||
{
|
||||
int ndev = 0, cardno = -1;
|
||||
while (!snd_card_next(&cardno) && cardno >= 0)
|
||||
ndev++;
|
||||
if (devno < 2*ndev)
|
||||
{
|
||||
if (devno & 1)
|
||||
snprintf(devname, nchar, "plughw:%d", devno/2);
|
||||
else snprintf(devname, nchar, "hw:%d", devno/2);
|
||||
}
|
||||
else if (devno <2*ndev + alsa_nnames)
|
||||
snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]);
|
||||
else snprintf(devname, nchar, "???");
|
||||
}
|
||||
|
||||
/* For each hardware card found, we list two devices, the "hard" and
|
||||
"plug" one. The card scan is derived from portaudio code. */
|
||||
void alsa_getdevs(char *indevlist, int *nindevs,
|
||||
char *outdevlist, int *noutdevs, int *canmulti,
|
||||
int maxndev, int devdescsize)
|
||||
{
|
||||
int ndev = 0, cardno = -1, i, j;
|
||||
*canmulti = 0; /* only one device; must be the same for input&output */
|
||||
while (!snd_card_next(&cardno) && cardno >= 0)
|
||||
{
|
||||
snd_ctl_t *ctl;
|
||||
snd_ctl_card_info_t *info;
|
||||
char devname[80];
|
||||
const char *desc;
|
||||
if (2 * ndev + 2 > maxndev)
|
||||
break;
|
||||
/* apparently, "cardno" is just a counter; but check that here */
|
||||
if (ndev != cardno)
|
||||
fprintf(stderr, "oops: ALSA cards not reported in order?\n");
|
||||
sprintf(devname, "hw:%d", cardno );
|
||||
/* fprintf(stderr, "\ntry %s...\n", devname); */
|
||||
if (snd_ctl_open(&ctl, devname, 0) >= 0)
|
||||
{
|
||||
snd_ctl_card_info_malloc(&info);
|
||||
snd_ctl_card_info(ctl, info);
|
||||
desc = snd_ctl_card_info_get_name(info);
|
||||
snd_ctl_card_info_free(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ALSA card scan error\n");
|
||||
desc = "???";
|
||||
}
|
||||
/* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */
|
||||
sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
|
||||
sprintf(indevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
|
||||
sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
|
||||
sprintf(outdevlist + (2*ndev + 1) * devdescsize, "%s (plug-in)", desc);
|
||||
ndev++;
|
||||
}
|
||||
for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++)
|
||||
{
|
||||
if (j >= maxndev)
|
||||
break;
|
||||
snprintf(indevlist + j * devdescsize, devdescsize, "%s",
|
||||
alsa_names[i]);
|
||||
}
|
||||
*nindevs = *noutdevs = j;
|
||||
}
|
||||
|
||||
|
|
@ -1,795 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
|
||||
"wave" devices, which is how ADAT boards appear to the WAVE API. */
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <MMSYSTEM.H>
|
||||
|
||||
/* ------------------------- audio -------------------------- */
|
||||
|
||||
static void nt_close_midiin(void);
|
||||
static void nt_noresync( void);
|
||||
|
||||
static void postflags(void);
|
||||
|
||||
#define NAPORTS 16 /* wini hack for multiple ADDA devices */
|
||||
#define CHANNELS_PER_DEVICE 2
|
||||
#define DEFAULTCHANS 2
|
||||
#define DEFAULTSRATE 44100
|
||||
#define SAMPSIZE 2
|
||||
|
||||
int nt_realdacblksize;
|
||||
#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
|
||||
|
||||
#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
|
||||
#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
|
||||
static int nt_naudiobuffer = DEFBUFFER;
|
||||
float sys_dacsr = DEFAULTSRATE;
|
||||
|
||||
static int nt_whichapi = API_MMIO;
|
||||
static int nt_meters; /* true if we're metering */
|
||||
static float nt_inmax; /* max input amplitude */
|
||||
static float nt_outmax; /* max output amplitude */
|
||||
static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
|
||||
|
||||
typedef struct _sbuf
|
||||
{
|
||||
HANDLE hData;
|
||||
HPSTR lpData; // pointer to waveform data memory
|
||||
HANDLE hWaveHdr;
|
||||
WAVEHDR *lpWaveHdr; // pointer to header structure
|
||||
} t_sbuf;
|
||||
|
||||
t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
|
||||
HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
|
||||
static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
|
||||
|
||||
t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
|
||||
HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
|
||||
static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
|
||||
|
||||
static void nt_waveinerror(char *s, int err)
|
||||
{
|
||||
char t[256];
|
||||
waveInGetErrorText(err, t, 256);
|
||||
fprintf(stderr, s, t);
|
||||
}
|
||||
|
||||
static void nt_waveouterror(char *s, int err)
|
||||
{
|
||||
char t[256];
|
||||
waveOutGetErrorText(err, t, 256);
|
||||
fprintf(stderr, s, t);
|
||||
}
|
||||
|
||||
static void wave_prep(t_sbuf *bp, int setdone)
|
||||
{
|
||||
WAVEHDR *wh;
|
||||
short *sp;
|
||||
int i;
|
||||
/*
|
||||
* Allocate and lock memory for the waveform data. The memory
|
||||
* for waveform data must be globally allocated with
|
||||
* GMEM_MOVEABLE and GMEM_SHARE flags.
|
||||
*/
|
||||
|
||||
if (!(bp->hData =
|
||||
GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
|
||||
(DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
|
||||
printf("alloc 1 failed\n");
|
||||
|
||||
if (!(bp->lpData =
|
||||
(HPSTR) GlobalLock(bp->hData)))
|
||||
printf("lock 1 failed\n");
|
||||
|
||||
/* Allocate and lock memory for the header. */
|
||||
|
||||
if (!(bp->hWaveHdr =
|
||||
GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
|
||||
printf("alloc 2 failed\n");
|
||||
|
||||
if (!(wh = bp->lpWaveHdr =
|
||||
(WAVEHDR *) GlobalLock(bp->hWaveHdr)))
|
||||
printf("lock 2 failed\n");
|
||||
|
||||
for (i = CHANNELS_PER_DEVICE * nt_realdacblksize,
|
||||
sp = (short *)bp->lpData; i--; )
|
||||
*sp++ = 0;
|
||||
|
||||
wh->lpData = bp->lpData;
|
||||
wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
|
||||
wh->dwFlags = 0;
|
||||
wh->dwLoops = 0L;
|
||||
wh->lpNext = 0;
|
||||
wh->reserved = 0;
|
||||
/* optionally (for writing) set DONE flag as if we had queued them */
|
||||
if (setdone)
|
||||
wh->dwFlags = WHDR_DONE;
|
||||
}
|
||||
|
||||
static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
|
||||
|
||||
int mmio_do_open_audio(void)
|
||||
{
|
||||
PCMWAVEFORMAT form;
|
||||
int i, j;
|
||||
UINT mmresult;
|
||||
int nad, nda;
|
||||
static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
|
||||
if (sys_verbose)
|
||||
post("%d devices in, %d devices out",
|
||||
nt_nwavein, nt_nwaveout);
|
||||
|
||||
form.wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
form.wf.nChannels = CHANNELS_PER_DEVICE;
|
||||
form.wf.nSamplesPerSec = sys_dacsr;
|
||||
form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
|
||||
form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
|
||||
form.wBitsPerSample = 8 * SAMPSIZE;
|
||||
|
||||
if (nt_nwavein <= 1 && nt_nwaveout <= 1)
|
||||
nt_noresync();
|
||||
|
||||
if (nindevsprepped < nt_nwavein)
|
||||
{
|
||||
for (i = nindevsprepped; i < nt_nwavein; i++)
|
||||
for (j = 0; j < naudioprepped; j++)
|
||||
wave_prep(&ntsnd_invec[i][j], 0);
|
||||
nindevsprepped = nt_nwavein;
|
||||
}
|
||||
if (noutdevsprepped < nt_nwaveout)
|
||||
{
|
||||
for (i = noutdevsprepped; i < nt_nwaveout; i++)
|
||||
for (j = 0; j < naudioprepped; j++)
|
||||
wave_prep(&ntsnd_outvec[i][j], 1);
|
||||
noutdevsprepped = nt_nwaveout;
|
||||
}
|
||||
if (naudioprepped < nt_naudiobuffer)
|
||||
{
|
||||
for (j = naudioprepped; j < nt_naudiobuffer; j++)
|
||||
{
|
||||
for (i = 0; i < nt_nwavein; i++)
|
||||
wave_prep(&ntsnd_invec[i][j], 0);
|
||||
for (i = 0; i < nt_nwaveout; i++)
|
||||
wave_prep(&ntsnd_outvec[i][j], 1);
|
||||
}
|
||||
naudioprepped = nt_naudiobuffer;
|
||||
}
|
||||
for (nad=0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
/* Open waveform device(s), sucessively numbered, for input */
|
||||
|
||||
mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
|
||||
(WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
|
||||
|
||||
if (sys_verbose)
|
||||
printf("opened adc device %d with return %d\n",
|
||||
nt_whichadc+nad,mmresult);
|
||||
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
{
|
||||
nt_waveinerror("waveInOpen: %s\n", mmresult);
|
||||
nt_nwavein = nad; /* nt_nwavein = 0 wini */
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < nt_naudiobuffer; i++)
|
||||
{
|
||||
mmresult = waveInPrepareHeader(ntsnd_indev[nad],
|
||||
ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveinerror("waveinprepareheader: %s\n", mmresult);
|
||||
mmresult = waveInAddBuffer(ntsnd_indev[nad],
|
||||
ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* quickly start them all together */
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
waveInStart(ntsnd_indev[nad]);
|
||||
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
/* Open a waveform device for output in sucessiv device numbering*/
|
||||
mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
|
||||
(WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
|
||||
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,"opened dac device %d, with return %d\n",
|
||||
nt_whichdac +nda, mmresult);
|
||||
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
{
|
||||
fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
|
||||
nt_waveouterror("waveOutOpen device: %s\n", mmresult);
|
||||
nt_nwaveout = nda;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void mmio_close_audio( void)
|
||||
{
|
||||
int errcode;
|
||||
int nda, nad;
|
||||
if (sys_verbose)
|
||||
post("closing audio...");
|
||||
|
||||
for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
|
||||
{
|
||||
errcode = waveOutReset(ntsnd_outdev[nda]);
|
||||
if (errcode != MMSYSERR_NOERROR)
|
||||
printf("error resetting output %d: %d\n", nda, errcode);
|
||||
errcode = waveOutClose(ntsnd_outdev[nda]);
|
||||
if (errcode != MMSYSERR_NOERROR)
|
||||
printf("error closing output %d: %d\n",nda , errcode);
|
||||
}
|
||||
nt_nwaveout = 0;
|
||||
|
||||
for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
|
||||
{
|
||||
errcode = waveInReset(ntsnd_indev[nad]);
|
||||
if (errcode != MMSYSERR_NOERROR)
|
||||
printf("error resetting input: %d\n", errcode);
|
||||
errcode = waveInClose(ntsnd_indev[nad]);
|
||||
if (errcode != MMSYSERR_NOERROR)
|
||||
printf("error closing input: %d\n", errcode);
|
||||
}
|
||||
nt_nwavein = 0;
|
||||
}
|
||||
|
||||
|
||||
#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
|
||||
#define DACJITTER 10
|
||||
|
||||
static int nt_adcjitterbufsallowed = ADCJITTER;
|
||||
static int nt_dacjitterbufsallowed = DACJITTER;
|
||||
|
||||
/* ------------- MIDI time stamping from audio clock ------------ */
|
||||
|
||||
#ifdef MIDI_TIMESTAMP
|
||||
|
||||
static double nt_hibuftime;
|
||||
static double initsystime = -1;
|
||||
|
||||
/* call this whenever we reset audio */
|
||||
static void nt_resetmidisync(void)
|
||||
{
|
||||
initsystime = clock_getsystime();
|
||||
nt_hibuftime = sys_getrealtime();
|
||||
}
|
||||
|
||||
/* call this whenever we're idled waiting for audio to be ready.
|
||||
The routine maintains a high and low water point for the difference
|
||||
between real and DAC time. */
|
||||
|
||||
static void nt_midisync(void)
|
||||
{
|
||||
double jittersec, diff;
|
||||
|
||||
if (initsystime == -1) nt_resetmidisync();
|
||||
jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
|
||||
nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
|
||||
* nt_realdacblksize / sys_getsr();
|
||||
diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
|
||||
if (diff > nt_hibuftime) nt_hibuftime = diff;
|
||||
if (diff < nt_hibuftime - jittersec)
|
||||
{
|
||||
post("jitter excess %d %f", dac, diff);
|
||||
nt_resetmidisync();
|
||||
}
|
||||
}
|
||||
|
||||
static double nt_midigettimefor(LARGE_INTEGER timestamp)
|
||||
{
|
||||
/* this is broken now... used to work when "timestamp" was derived from
|
||||
QueryPerformanceCounter() instead of the gates approved
|
||||
timeGetSystemTime() call in the MIDI callback routine below. */
|
||||
return (nt_tixtotime(timestamp) - nt_hibuftime);
|
||||
}
|
||||
#endif /* MIDI_TIMESTAMP */
|
||||
|
||||
|
||||
static int nt_fill = 0;
|
||||
#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
|
||||
#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
|
||||
#define MAXRESYNC 500
|
||||
|
||||
#if 0 /* this is used for debugging */
|
||||
static void nt_printaudiostatus(void)
|
||||
{
|
||||
int nad, nda;
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
|
||||
int firstphasedone = -1, firstphasebusy = -1;
|
||||
for (count = 0; count < nt_naudiobuffer; count++)
|
||||
{
|
||||
int donethis =
|
||||
(ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
|
||||
int donenext =
|
||||
(ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
|
||||
if (donethis && !donenext)
|
||||
{
|
||||
if (firstphasebusy >= 0) goto multipleadc;
|
||||
firstphasebusy = count;
|
||||
}
|
||||
if (!donethis && donenext)
|
||||
{
|
||||
if (firstphasedone >= 0) goto multipleadc;
|
||||
firstphasedone = count;
|
||||
}
|
||||
phase2 = phase3;
|
||||
phase3 = WRAPFWD(phase2 + 1);
|
||||
}
|
||||
post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
|
||||
firstphasedone);
|
||||
continue;
|
||||
multipleadc:
|
||||
startpost("nad %d phase %d: oops:", nad, phase);
|
||||
for (count = 0; count < nt_naudiobuffer; count++)
|
||||
{
|
||||
char buf[80];
|
||||
sprintf(buf, " %d",
|
||||
(ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
|
||||
poststring(buf);
|
||||
}
|
||||
endpost();
|
||||
}
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nad];
|
||||
int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
|
||||
int firstphasedone = -1, firstphasebusy = -1;
|
||||
for (count = 0; count < nt_naudiobuffer; count++)
|
||||
{
|
||||
int donethis =
|
||||
(ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
|
||||
int donenext =
|
||||
(ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
|
||||
if (donethis && !donenext)
|
||||
{
|
||||
if (firstphasebusy >= 0) goto multipledac;
|
||||
firstphasebusy = count;
|
||||
}
|
||||
if (!donethis && donenext)
|
||||
{
|
||||
if (firstphasedone >= 0) goto multipledac;
|
||||
firstphasedone = count;
|
||||
}
|
||||
phase2 = phase3;
|
||||
phase3 = WRAPFWD(phase2 + 1);
|
||||
}
|
||||
if (firstphasebusy < 0) post("nda %d phase %d all %d",
|
||||
nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
|
||||
else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
|
||||
firstphasedone);
|
||||
continue;
|
||||
multipledac:
|
||||
startpost("nda %d phase %d: oops:", nda, phase);
|
||||
for (count = 0; count < nt_naudiobuffer; count++)
|
||||
{
|
||||
char buf[80];
|
||||
sprintf(buf, " %d",
|
||||
(ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
|
||||
poststring(buf);
|
||||
}
|
||||
endpost();
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/* this is a hack to avoid ever resyncing audio pointers in case for whatever
|
||||
reason the sync testing below gives false positives. */
|
||||
|
||||
static int nt_resync_cancelled;
|
||||
|
||||
static void nt_noresync( void)
|
||||
{
|
||||
nt_resync_cancelled = 1;
|
||||
}
|
||||
|
||||
static void nt_resyncaudio(void)
|
||||
{
|
||||
UINT mmresult;
|
||||
int nad, nda, count;
|
||||
if (nt_resync_cancelled)
|
||||
return;
|
||||
/* for each open input device, eat all buffers which are marked
|
||||
ready. The next one will thus be "busy". */
|
||||
post("resyncing audio");
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
for (count = 0; count < MAXRESYNC; count++)
|
||||
{
|
||||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
|
||||
if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
|
||||
if (inwavehdr->dwFlags & WHDR_PREPARED)
|
||||
waveInUnprepareHeader(ntsnd_indev[nad],
|
||||
inwavehdr, sizeof(WAVEHDR));
|
||||
inwavehdr->dwFlags = 0L;
|
||||
waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
|
||||
mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
|
||||
sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
|
||||
ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
|
||||
}
|
||||
if (count == MAXRESYNC) post("resync error 1");
|
||||
}
|
||||
/* Each output buffer which is "ready" is filled with zeros and
|
||||
queued. */
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
for (count = 0; count < MAXRESYNC; count++)
|
||||
{
|
||||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
|
||||
if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
|
||||
if (outwavehdr->dwFlags & WHDR_PREPARED)
|
||||
waveOutUnprepareHeader(ntsnd_outdev[nda],
|
||||
outwavehdr, sizeof(WAVEHDR));
|
||||
outwavehdr->dwFlags = 0L;
|
||||
memset((char *)(ntsnd_outvec[nda][phase].lpData),
|
||||
0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize));
|
||||
waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
|
||||
sizeof(WAVEHDR));
|
||||
mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
|
||||
sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
|
||||
ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
|
||||
}
|
||||
if (count == MAXRESYNC) post("resync error 2");
|
||||
}
|
||||
|
||||
#ifdef MIDI_TIMESTAMP
|
||||
nt_resetmidisync();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#define LATE 0
|
||||
#define RESYNC 1
|
||||
#define NOTHING 2
|
||||
static int nt_errorcount;
|
||||
static int nt_resynccount;
|
||||
static double nt_nextreporttime = -1;
|
||||
|
||||
void nt_logerror(int which)
|
||||
{
|
||||
#if 0
|
||||
post("error %d %d", count, which);
|
||||
if (which < NOTHING) nt_errorcount++;
|
||||
if (which == RESYNC) nt_resynccount++;
|
||||
if (sys_getrealtime() > nt_nextreporttime)
|
||||
{
|
||||
post("%d audio I/O error%s", nt_errorcount,
|
||||
(nt_errorcount > 1 ? "s" : ""));
|
||||
if (nt_resynccount) post("DAC/ADC sync error");
|
||||
nt_errorcount = nt_resynccount = 0;
|
||||
nt_nextreporttime = sys_getrealtime() - 5;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* system buffer with t_sample types for one tick */
|
||||
t_sample *sys_soundout;
|
||||
t_sample *sys_soundin;
|
||||
float sys_dacsr;
|
||||
|
||||
int mmio_send_dacs(void)
|
||||
{
|
||||
HMMIO hmmio;
|
||||
UINT mmresult;
|
||||
HANDLE hFormat;
|
||||
int i, j;
|
||||
short *sp1, *sp2;
|
||||
float *fp1, *fp2;
|
||||
int nextfill, doxfer = 0;
|
||||
int nda, nad;
|
||||
if (!nt_nwavein && !nt_nwaveout) return (0);
|
||||
|
||||
|
||||
if (nt_meters)
|
||||
{
|
||||
int i, n;
|
||||
float maxsamp;
|
||||
for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
|
||||
i < n; i++)
|
||||
{
|
||||
float f = sys_soundin[i];
|
||||
if (f > maxsamp) maxsamp = f;
|
||||
else if (-f > maxsamp) maxsamp = -f;
|
||||
}
|
||||
nt_inmax = maxsamp;
|
||||
for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
|
||||
i < n; i++)
|
||||
{
|
||||
float f = sys_soundout[i];
|
||||
if (f > maxsamp) maxsamp = f;
|
||||
else if (-f > maxsamp) maxsamp = -f;
|
||||
}
|
||||
nt_outmax = maxsamp;
|
||||
}
|
||||
|
||||
/* the "fill pointer" nt_fill controls where in the next
|
||||
I/O buffers we will write and/or read. If it's zero, we
|
||||
first check whether the buffers are marked "done". */
|
||||
|
||||
if (!nt_fill)
|
||||
{
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
|
||||
if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
|
||||
}
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
WAVEHDR *outwavehdr =
|
||||
ntsnd_outvec[nda][phase].lpWaveHdr;
|
||||
if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
|
||||
}
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
WAVEHDR *inwavehdr =
|
||||
ntsnd_invec[nad][phase].lpWaveHdr;
|
||||
if (inwavehdr->dwFlags & WHDR_PREPARED)
|
||||
waveInUnprepareHeader(ntsnd_indev[nad],
|
||||
inwavehdr, sizeof(WAVEHDR));
|
||||
}
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
|
||||
if (outwavehdr->dwFlags & WHDR_PREPARED)
|
||||
waveOutUnprepareHeader(ntsnd_outdev[nda],
|
||||
outwavehdr, sizeof(WAVEHDR));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert audio output to fixed-point and put it in the output
|
||||
buffer. */
|
||||
for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
|
||||
for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
|
||||
CHANNELS_PER_DEVICE * nt_fill;
|
||||
i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
|
||||
{
|
||||
for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
|
||||
j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
|
||||
{
|
||||
int x1 = 32767.f * *fp2;
|
||||
if (x1 > 32767) x1 = 32767;
|
||||
else if (x1 < -32767) x1 = -32767;
|
||||
*sp2 = x1;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(sys_soundout, 0,
|
||||
(DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
|
||||
|
||||
/* vice versa for the input buffer */
|
||||
|
||||
for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
|
||||
for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
|
||||
CHANNELS_PER_DEVICE * nt_fill;
|
||||
i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
|
||||
{
|
||||
for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
|
||||
j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
|
||||
{
|
||||
*fp2 = ((float)(1./32767.)) * (float)(*sp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nt_fill = nt_fill + DEFDACBLKSIZE;
|
||||
if (nt_fill == nt_realdacblksize)
|
||||
{
|
||||
nt_fill = 0;
|
||||
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
HWAVEIN device = ntsnd_indev[nad];
|
||||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
|
||||
waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
|
||||
mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
|
||||
ntsnd_inphase[nad] = WRAPFWD(phase + 1);
|
||||
}
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
HWAVEOUT device = ntsnd_outdev[nda];
|
||||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
|
||||
waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
|
||||
mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
|
||||
if (mmresult != MMSYSERR_NOERROR)
|
||||
nt_waveouterror("waveOutWrite: %s\n", mmresult);
|
||||
ntsnd_outphase[nda] = WRAPFWD(phase + 1);
|
||||
}
|
||||
|
||||
/* check for DAC underflow or ADC overflow. */
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
|
||||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
|
||||
if (inwavehdr->dwFlags & WHDR_DONE) goto late;
|
||||
}
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
|
||||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
|
||||
if (outwavehdr->dwFlags & WHDR_DONE) goto late;
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
|
||||
late:
|
||||
|
||||
nt_logerror(LATE);
|
||||
nt_resyncaudio();
|
||||
return (1);
|
||||
|
||||
idle:
|
||||
|
||||
/* If more than nt_adcjitterbufsallowed ADC buffers are ready
|
||||
on any input device, resynchronize */
|
||||
|
||||
for (nad = 0; nad < nt_nwavein; nad++)
|
||||
{
|
||||
int phase = ntsnd_inphase[nad];
|
||||
WAVEHDR *inwavehdr =
|
||||
ntsnd_invec[nad]
|
||||
[WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
|
||||
if (inwavehdr->dwFlags & WHDR_DONE)
|
||||
{
|
||||
nt_resyncaudio();
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* test dac sync the same way */
|
||||
for (nda = 0; nda < nt_nwaveout; nda++)
|
||||
{
|
||||
int phase = ntsnd_outphase[nda];
|
||||
WAVEHDR *outwavehdr =
|
||||
ntsnd_outvec[nda]
|
||||
[WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
|
||||
if (outwavehdr->dwFlags & WHDR_DONE)
|
||||
{
|
||||
nt_resyncaudio();
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#ifdef MIDI_TIMESTAMP
|
||||
nt_midisync();
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ------------------- public routines -------------------------- */
|
||||
|
||||
void mmio_open_audio(int naudioindev, int *audioindev,
|
||||
int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
|
||||
int nchoutdev, int *choutdev, int rate) /* IOhannes */
|
||||
{
|
||||
int nbuf;
|
||||
|
||||
nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
|
||||
nbuf = sys_advance_samples/nt_realdacblksize;
|
||||
if (nbuf >= MAXBUFFER)
|
||||
{
|
||||
fprintf(stderr, "pd: audio buffering maxed out to %d\n",
|
||||
(int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
|
||||
nbuf = MAXBUFFER;
|
||||
}
|
||||
else if (nbuf < 4) nbuf = 4;
|
||||
fprintf(stderr, "%d audio buffers\n", nbuf);
|
||||
nt_naudiobuffer = nbuf;
|
||||
if (nt_adcjitterbufsallowed > nbuf - 2)
|
||||
nt_adcjitterbufsallowed = nbuf - 2;
|
||||
if (nt_dacjitterbufsallowed > nbuf - 2)
|
||||
nt_dacjitterbufsallowed = nbuf - 2;
|
||||
|
||||
nt_nwavein = sys_inchannels / 2;
|
||||
nt_nwaveout = sys_outchannels / 2;
|
||||
nt_whichadc = (naudioindev < 1 ?
|
||||
(nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]);
|
||||
nt_whichdac = (naudiooutdev < 1 ?
|
||||
(nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
|
||||
if (naudiooutdev > 1 || naudioindev > 1)
|
||||
post("separate audio device choice not supported; using sequential devices.");
|
||||
mmio_do_open_audio();
|
||||
}
|
||||
|
||||
|
||||
void mmio_reportidle(void)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* list the audio and MIDI device names */
|
||||
void mmio_listdevs(void)
|
||||
{
|
||||
UINT wRtn, ndevices;
|
||||
unsigned int i;
|
||||
|
||||
ndevices = waveInGetNumDevs();
|
||||
for (i = 0; i < ndevices; i++)
|
||||
{
|
||||
WAVEINCAPS wicap;
|
||||
wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
|
||||
sizeof(wicap));
|
||||
if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
|
||||
else fprintf(stderr,
|
||||
"audio input device #%d: %s\n", i+1, wicap.szPname);
|
||||
}
|
||||
|
||||
ndevices = waveOutGetNumDevs();
|
||||
for (i = 0; i < ndevices; i++)
|
||||
{
|
||||
WAVEOUTCAPS wocap;
|
||||
wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
|
||||
sizeof(wocap));
|
||||
if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
|
||||
else fprintf(stderr,
|
||||
"audio output device #%d: %s\n", i+1, wocap.szPname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void mmio_getdevs(char *indevlist, int *nindevs,
|
||||
char *outdevlist, int *noutdevs, int *canmulti,
|
||||
int maxndev, int devdescsize)
|
||||
{
|
||||
int wRtn, ndev, i;
|
||||
|
||||
*canmulti = 2; /* supports multiple devices */
|
||||
ndev = waveInGetNumDevs();
|
||||
if (ndev > maxndev)
|
||||
ndev = maxndev;
|
||||
*nindevs = ndev;
|
||||
for (i = 0; i < ndev; i++)
|
||||
{
|
||||
WAVEINCAPS wicap;
|
||||
wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
|
||||
sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
|
||||
}
|
||||
|
||||
ndev = waveOutGetNumDevs();
|
||||
if (ndev > maxndev)
|
||||
ndev = maxndev;
|
||||
*noutdevs = ndev;
|
||||
for (i = 0; i < ndev; i++)
|
||||
{
|
||||
WAVEOUTCAPS wocap;
|
||||
wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
|
||||
sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,845 +0,0 @@
|
|||
/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
|
||||
* Winfried Ritsch, Karl MacMillan, and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* this file inputs and outputs audio using the OSS API available on linux. */
|
||||
|
||||
#ifdef USEAPI_OSS
|
||||
|
||||
#include <linux/soundcard.h>
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
/* Defines */
|
||||
#define DEBUG(x) x
|
||||
#define DEBUG2(x) {x;}
|
||||
|
||||
#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
|
||||
#define OSS_MAXDEV 4 /* maximum number of input or output devices */
|
||||
#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
|
||||
#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
|
||||
#define OSS_DEFAULTCH 2
|
||||
#define RME_DEFAULTCH 8 /* need this even if RME undefined */
|
||||
typedef int16_t t_oss_int16;
|
||||
typedef int32_t t_oss_int32;
|
||||
#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
|
||||
#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
|
||||
#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
|
||||
#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
|
||||
|
||||
/* GLOBALS */
|
||||
static int linux_meters; /* true if we're metering */
|
||||
static float linux_inmax; /* max input amplitude */
|
||||
static float linux_outmax; /* max output amplitude */
|
||||
static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
|
||||
|
||||
/* our device handles */
|
||||
|
||||
typedef struct _oss_dev
|
||||
{
|
||||
int d_fd;
|
||||
unsigned int d_space; /* bytes available for writing/reading */
|
||||
int d_bufsize; /* total buffer size in blocks for this device */
|
||||
int d_dropcount; /* # of buffers to drop for resync (output only) */
|
||||
unsigned int d_nchannels; /* number of channels for this device */
|
||||
unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
|
||||
} t_oss_dev;
|
||||
|
||||
static t_oss_dev linux_dacs[OSS_MAXDEV];
|
||||
static t_oss_dev linux_adcs[OSS_MAXDEV];
|
||||
static int linux_noutdevs = 0;
|
||||
static int linux_nindevs = 0;
|
||||
|
||||
/* exported variables */
|
||||
float sys_dacsr;
|
||||
t_sample *sys_soundout;
|
||||
t_sample *sys_soundin;
|
||||
|
||||
/* OSS-specific private variables */
|
||||
static int oss_blockmode = 1; /* flag to use "blockmode" */
|
||||
static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
|
||||
static char ossdsp[] = "/dev/dsp%d";
|
||||
|
||||
/* don't assume we can turn all 31 bits when doing float-to-fix;
|
||||
otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
|
||||
#define FMAX 0x7ffff000
|
||||
#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
|
||||
|
||||
|
||||
/* ------------- private routines for all APIS ------------------- */
|
||||
|
||||
static void linux_flush_all_underflows_to_zero(void)
|
||||
{
|
||||
/*
|
||||
TODO: Implement similar thing for linux (GGeiger)
|
||||
|
||||
One day we will figure this out, I hope, because it
|
||||
costs CPU time dearly on Intel - LT
|
||||
*/
|
||||
/* union fpc_csr f;
|
||||
f.fc_word = get_fpc_csr();
|
||||
f.fc_struct.flush = 1;
|
||||
set_fpc_csr(f.fc_word);
|
||||
*/
|
||||
}
|
||||
|
||||
static int oss_ndev = 0;
|
||||
|
||||
/* find out how many OSS devices we have. Since this has to
|
||||
open the devices to find out if they're there, we have
|
||||
to be called before audio is actually started up. So we
|
||||
cache the results, which in effect are the number of available
|
||||
devices. */
|
||||
void oss_init(void)
|
||||
{
|
||||
int fd, i;
|
||||
static int countedthem = 0;
|
||||
if (countedthem)
|
||||
return;
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
char devname[100];
|
||||
if (i == 0)
|
||||
strcpy(devname, "/dev/dsp");
|
||||
else sprintf(devname, "/dev/dsp%d", i);
|
||||
if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1)
|
||||
{
|
||||
oss_ndev++;
|
||||
close(fd);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
countedthem = 1;
|
||||
}
|
||||
|
||||
|
||||
void oss_set32bit( void)
|
||||
{
|
||||
oss_32bit = 1;
|
||||
}
|
||||
|
||||
|
||||
typedef struct _multidev {
|
||||
int fd;
|
||||
int channels;
|
||||
int format;
|
||||
} t_multidev;
|
||||
|
||||
int oss_reset(int fd) {
|
||||
int err;
|
||||
if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
|
||||
error("OSS: Could not reset");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
|
||||
but is proposed by Guenter Geiger to support extending OSS to handle
|
||||
32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
|
||||
I'm not clear why this isn't called AFMT_S32_[SLN]E... */
|
||||
|
||||
#ifndef AFMT_S32_BLOCKED
|
||||
#define AFMT_S32_BLOCKED 0x0000400
|
||||
#endif
|
||||
|
||||
void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
|
||||
{ /* IOhannes */
|
||||
int orig, param, nblk, fd = dev->d_fd, wantformat;
|
||||
int nchannels = dev->d_nchannels;
|
||||
int advwas = sys_schedadvance;
|
||||
|
||||
audio_buf_info ainfo;
|
||||
|
||||
/* IOhannes :
|
||||
* pd is very likely to crash if different formats are used on
|
||||
multiple soundcards
|
||||
*/
|
||||
|
||||
/* set resolution - first try 4 byte samples */
|
||||
if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,¶m) >= 0) &&
|
||||
(param & AFMT_S32_BLOCKED))
|
||||
{
|
||||
wantformat = AFMT_S32_BLOCKED;
|
||||
dev->d_bytespersamp = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
wantformat = AFMT_S16_NE;
|
||||
dev->d_bytespersamp = 2;
|
||||
}
|
||||
param = wantformat;
|
||||
|
||||
if (sys_verbose)
|
||||
post("bytes per sample = %d", dev->d_bytespersamp);
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFMT, ¶m) == -1)
|
||||
fprintf(stderr,"OSS: Could not set DSP format\n");
|
||||
else if (wantformat != param)
|
||||
fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
|
||||
wantformat, param);
|
||||
|
||||
/* sample rate */
|
||||
orig = param = srate;
|
||||
if (ioctl(fd, SNDCTL_DSP_SPEED, ¶m) == -1)
|
||||
fprintf(stderr,"OSS: Could not set sampling rate for device\n");
|
||||
else if( orig != param )
|
||||
fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
|
||||
orig, param );
|
||||
|
||||
if (oss_blockmode && !skipblocksize)
|
||||
{
|
||||
int fragbytes, logfragsize, nfragment;
|
||||
/* setting fragment count and size. */
|
||||
if (!linux_fragsize)
|
||||
{
|
||||
linux_fragsize = OSS_DEFFRAGSIZE;
|
||||
while (linux_fragsize > DEFDACBLKSIZE
|
||||
&& linux_fragsize * 4 > sys_advance_samples)
|
||||
linux_fragsize = linux_fragsize/2;
|
||||
}
|
||||
|
||||
/* post("adv_samples %d", sys_advance_samples); */
|
||||
nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
|
||||
|
||||
fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
|
||||
logfragsize = ilog2(fragbytes);
|
||||
|
||||
if (fragbytes != (1 << logfragsize))
|
||||
post("warning: OSS takes only power of 2 blocksize; using %d",
|
||||
(1 << logfragsize)/(dev->d_bytespersamp * nchannels));
|
||||
if (sys_verbose)
|
||||
post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
|
||||
|
||||
param = orig = (nfragment<<16) + logfragsize;
|
||||
if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, ¶m) == -1)
|
||||
error("OSS: Could not set or read fragment size\n");
|
||||
if (param != orig)
|
||||
{
|
||||
nfragment = ((param >> 16) & 0xffff);
|
||||
logfragsize = (param & 0xffff);
|
||||
post("warning: actual fragments %d, blocksize %d",
|
||||
nfragment, (1 << logfragsize));
|
||||
}
|
||||
if (sys_verbose)
|
||||
post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
|
||||
}
|
||||
if (dac)
|
||||
{
|
||||
/* use "free space" to learn the buffer size. Normally you
|
||||
should set this to your own desired value; but this seems not
|
||||
to be implemented uniformly across different sound cards. LATER
|
||||
we should figure out what to do if the requested scheduler advance
|
||||
is greater than this buffer size; for now, we just print something
|
||||
out. */
|
||||
|
||||
int defect;
|
||||
if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
|
||||
fprintf(stderr,"OSS: ioctl on output device failed");
|
||||
dev->d_bufsize = ainfo.bytes;
|
||||
|
||||
defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
|
||||
- dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
|
||||
if (defect > 0)
|
||||
{
|
||||
if (sys_verbose || defect > (dev->d_bufsize >> 2))
|
||||
fprintf(stderr,
|
||||
"OSS: requested audio buffer size %d limited to %d\n",
|
||||
sys_advance_samples * (dev->d_bytespersamp * nchannels),
|
||||
dev->d_bufsize);
|
||||
sys_advance_samples =
|
||||
(dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
|
||||
(dev->d_bytespersamp *nchannels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int oss_setchannels(int fd, int wantchannels, char *devname)
|
||||
{ /* IOhannes */
|
||||
int param = wantchannels;
|
||||
|
||||
while (param>1) {
|
||||
int save = param;
|
||||
if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) {
|
||||
error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
|
||||
} else {
|
||||
if (param == save) return (param);
|
||||
}
|
||||
param=save-1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define O_AUDIOFLAG 0 /* O_NDELAY */
|
||||
|
||||
int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
|
||||
int noutdev, int *outdev, int nchout, int *chout, int rate)
|
||||
{ /* IOhannes */
|
||||
int capabilities = 0;
|
||||
int inchannels = 0, outchannels = 0;
|
||||
char devname[20];
|
||||
int n, i, fd;
|
||||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
|
||||
int num_devs = 0;
|
||||
int wantmore=0;
|
||||
int spread = 0;
|
||||
audio_buf_info ainfo;
|
||||
|
||||
linux_nindevs = linux_noutdevs = 0;
|
||||
|
||||
|
||||
/* mark input devices unopened */
|
||||
for (i = 0; i < OSS_MAXDEV; i++)
|
||||
linux_adcs[i].d_fd = -1;
|
||||
|
||||
/* open output devices */
|
||||
wantmore=0;
|
||||
if (noutdev < 0 || nindev < 0)
|
||||
bug("linux_open_audio");
|
||||
|
||||
for (n = 0; n < noutdev; n++)
|
||||
{
|
||||
int gotchans, j, inindex = -1;
|
||||
int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
|
||||
int wantchannels = (nchout>n) ? chout[n] : wantmore;
|
||||
fd = -1;
|
||||
if (!wantchannels)
|
||||
goto end_out_loop;
|
||||
|
||||
if (thisdevice > 1)
|
||||
sprintf(devname, "/dev/dsp%d", thisdevice-1);
|
||||
else sprintf(devname, "/dev/dsp");
|
||||
|
||||
/* search for input request for same device. Succeed only
|
||||
if the number of channels matches. */
|
||||
for (j = 0; j < nindev; j++)
|
||||
if (indev[j] == thisdevice && chin[j] == wantchannels)
|
||||
inindex = j;
|
||||
|
||||
/* if the same device is requested for input and output,
|
||||
try to open it read/write */
|
||||
if (inindex >= 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
|
||||
{
|
||||
post("%s (read/write): %s", devname, strerror(errno));
|
||||
post("(now will try write-only...)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sys_verbose)
|
||||
post("opened %s for reading and writing\n", devname);
|
||||
linux_adcs[inindex].d_fd = fd;
|
||||
}
|
||||
}
|
||||
/* if that didn't happen or if it failed, try write-only */
|
||||
if (fd == -1)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
|
||||
{
|
||||
post("%s (writeonly): %s",
|
||||
devname, strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (sys_verbose)
|
||||
post("opened %s for writing only\n", devname);
|
||||
}
|
||||
if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
|
||||
error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
|
||||
|
||||
gotchans = oss_setchannels(fd,
|
||||
(wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
|
||||
devname);
|
||||
|
||||
if (sys_verbose)
|
||||
post("opened audio output on %s; got %d channels",
|
||||
devname, gotchans);
|
||||
|
||||
if (gotchans < 2)
|
||||
{
|
||||
/* can't even do stereo? just give up. */
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
linux_dacs[linux_noutdevs].d_nchannels = gotchans;
|
||||
linux_dacs[linux_noutdevs].d_fd = fd;
|
||||
oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
|
||||
|
||||
linux_noutdevs++;
|
||||
outchannels += gotchans;
|
||||
if (inindex >= 0)
|
||||
{
|
||||
linux_adcs[inindex].d_nchannels = gotchans;
|
||||
chin[inindex] = gotchans;
|
||||
}
|
||||
}
|
||||
/* LATER think about spreading large numbers of channels over
|
||||
various dsp's and vice-versa */
|
||||
wantmore = wantchannels - gotchans;
|
||||
end_out_loop: ;
|
||||
}
|
||||
|
||||
/* open input devices */
|
||||
wantmore = 0;
|
||||
for (n = 0; n < nindev; n++)
|
||||
{
|
||||
int gotchans=0;
|
||||
int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
|
||||
int wantchannels = (nchin>n)?chin[n]:wantmore;
|
||||
int alreadyopened = 0;
|
||||
if (!wantchannels)
|
||||
goto end_in_loop;
|
||||
|
||||
if (thisdevice > 1)
|
||||
sprintf(devname, "/dev/dsp%d", thisdevice - 1);
|
||||
else sprintf(devname, "/dev/dsp");
|
||||
|
||||
sys_setalarm(1000000);
|
||||
|
||||
/* perhaps it's already open from the above? */
|
||||
if (linux_dacs[n].d_fd >= 0)
|
||||
{
|
||||
fd = linux_dacs[n].d_fd;
|
||||
alreadyopened = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise try to open it here. */
|
||||
if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
|
||||
{
|
||||
post("%s (readonly): %s", devname, strerror(errno));
|
||||
goto end_in_loop;
|
||||
}
|
||||
if (sys_verbose)
|
||||
post("opened %s for reading only\n", devname);
|
||||
}
|
||||
linux_adcs[linux_nindevs].d_fd = fd;
|
||||
gotchans = oss_setchannels(fd,
|
||||
(wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
|
||||
devname);
|
||||
if (sys_verbose)
|
||||
post("opened audio input device %s; got %d channels",
|
||||
devname, gotchans);
|
||||
|
||||
if (gotchans < 1)
|
||||
{
|
||||
close(fd);
|
||||
goto end_in_loop;
|
||||
}
|
||||
|
||||
linux_adcs[linux_nindevs].d_nchannels = gotchans;
|
||||
|
||||
oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
|
||||
|
||||
inchannels += gotchans;
|
||||
linux_nindevs++;
|
||||
|
||||
wantmore = wantchannels-gotchans;
|
||||
/* LATER think about spreading large numbers of channels over
|
||||
various dsp's and vice-versa */
|
||||
end_in_loop: ;
|
||||
}
|
||||
|
||||
/* We have to do a read to start the engine. This is
|
||||
necessary because sys_send_dacs waits until the input
|
||||
buffer is filled and only reads on a filled buffer.
|
||||
This is good, because it's a way to make sure that we
|
||||
will not block. But I wonder why we only have to read
|
||||
from one of the devices and not all of them??? */
|
||||
|
||||
if (linux_nindevs)
|
||||
{
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
|
||||
read(linux_adcs[0].d_fd, buf,
|
||||
linux_adcs[0].d_bytespersamp *
|
||||
linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "...done.\n");
|
||||
}
|
||||
sys_setalarm(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void oss_close_audio( void)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<linux_nindevs;i++)
|
||||
close(linux_adcs[i].d_fd);
|
||||
|
||||
for (i=0;i<linux_noutdevs;i++)
|
||||
close(linux_dacs[i].d_fd);
|
||||
|
||||
linux_nindevs = linux_noutdevs = 0;
|
||||
}
|
||||
|
||||
static int linux_dacs_write(int fd,void* buf,long bytes)
|
||||
{
|
||||
return write(fd, buf, bytes);
|
||||
}
|
||||
|
||||
static int linux_adcs_read(int fd,void* buf,long bytes)
|
||||
{
|
||||
return read(fd, buf, bytes);
|
||||
}
|
||||
|
||||
/* query audio devices for "available" data size. */
|
||||
static void oss_calcspace(void)
|
||||
{
|
||||
int dev;
|
||||
audio_buf_info ainfo;
|
||||
for (dev=0; dev < linux_noutdevs; dev++)
|
||||
{
|
||||
if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
|
||||
fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
|
||||
linux_dacs[dev].d_space = ainfo.bytes;
|
||||
}
|
||||
|
||||
for (dev = 0; dev < linux_nindevs; dev++)
|
||||
{
|
||||
if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
|
||||
fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
|
||||
dev, linux_adcs[dev].d_fd);
|
||||
linux_adcs[dev].d_space = ainfo.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void linux_audiostatus(void)
|
||||
{
|
||||
int dev;
|
||||
if (!oss_blockmode)
|
||||
{
|
||||
oss_calcspace();
|
||||
for (dev=0; dev < linux_noutdevs; dev++)
|
||||
fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
|
||||
|
||||
for (dev = 0; dev < linux_nindevs; dev++)
|
||||
fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* this call resyncs audio output and input which will cause discontinuities
|
||||
in audio output and/or input. */
|
||||
|
||||
static void oss_doresync( void)
|
||||
{
|
||||
int dev, zeroed = 0, wantsize;
|
||||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
|
||||
audio_buf_info ainfo;
|
||||
|
||||
/* 1. if any input devices are ahead (have more than 1 buffer stored),
|
||||
drop one or more buffers worth */
|
||||
for (dev = 0; dev < linux_nindevs; dev++)
|
||||
{
|
||||
if (linux_adcs[dev].d_space == 0)
|
||||
{
|
||||
linux_adcs_read(linux_adcs[dev].d_fd, buf,
|
||||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
|
||||
linux_adcs[dev].d_bytespersamp));
|
||||
}
|
||||
else while (linux_adcs[dev].d_space >
|
||||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
|
||||
linux_adcs[dev].d_bytespersamp))
|
||||
{
|
||||
linux_adcs_read(linux_adcs[dev].d_fd, buf,
|
||||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
|
||||
linux_adcs[dev].d_bytespersamp));
|
||||
if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
|
||||
{
|
||||
fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
|
||||
dev, linux_adcs[dev].d_fd);
|
||||
break;
|
||||
}
|
||||
linux_adcs[dev].d_space = ainfo.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. if any output devices are behind, feed them zeros to catch them
|
||||
up */
|
||||
for (dev = 0; dev < linux_noutdevs; dev++)
|
||||
{
|
||||
while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
|
||||
sys_advance_samples * (linux_dacs[dev].d_nchannels *
|
||||
linux_dacs[dev].d_bytespersamp))
|
||||
{
|
||||
if (!zeroed)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
|
||||
i++)
|
||||
buf[i] = 0;
|
||||
zeroed = 1;
|
||||
}
|
||||
linux_dacs_write(linux_dacs[dev].d_fd, buf,
|
||||
OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
|
||||
linux_dacs[dev].d_bytespersamp));
|
||||
if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
|
||||
{
|
||||
fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
|
||||
dev, linux_dacs[dev].d_fd);
|
||||
break;
|
||||
}
|
||||
linux_dacs[dev].d_space = ainfo.bytes;
|
||||
}
|
||||
}
|
||||
/* 3. if any DAC devices are too far ahead, plan to drop the
|
||||
number of frames which will let the others catch up. */
|
||||
for (dev = 0; dev < linux_noutdevs; dev++)
|
||||
{
|
||||
if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
|
||||
(sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
|
||||
linux_dacs[dev].d_bytespersamp)
|
||||
{
|
||||
linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
|
||||
(linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
|
||||
(linux_dacs[dev].d_nchannels *
|
||||
linux_dacs[dev].d_bytespersamp) ;
|
||||
}
|
||||
else linux_dacs[dev].d_dropcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int oss_send_dacs(void)
|
||||
{
|
||||
t_sample *fp1, *fp2;
|
||||
long fill;
|
||||
int i, j, dev, rtnval = SENDDACS_YES;
|
||||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
|
||||
t_oss_int16 *sp;
|
||||
t_oss_int32 *lp;
|
||||
/* the maximum number of samples we should have in the ADC buffer */
|
||||
int idle = 0;
|
||||
int thischan;
|
||||
t_time timeref, timenow;
|
||||
|
||||
if (!linux_nindevs && !linux_noutdevs)
|
||||
return (SENDDACS_NO);
|
||||
|
||||
if (!oss_blockmode)
|
||||
{
|
||||
/* determine whether we're idle. This is true if either (1)
|
||||
some input device has less than one buffer to read or (2) some
|
||||
output device has fewer than (sys_advance_samples) blocks buffered
|
||||
already. */
|
||||
oss_calcspace();
|
||||
|
||||
for (dev=0; dev < linux_noutdevs; dev++)
|
||||
if (linux_dacs[dev].d_dropcount ||
|
||||
(linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
|
||||
sys_advance_samples * linux_dacs[dev].d_bytespersamp *
|
||||
linux_dacs[dev].d_nchannels))
|
||||
idle = 1;
|
||||
for (dev=0; dev < linux_nindevs; dev++)
|
||||
if (linux_adcs[dev].d_space <
|
||||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
|
||||
linux_adcs[dev].d_bytespersamp))
|
||||
idle = 1;
|
||||
}
|
||||
|
||||
if (idle && !oss_blockmode)
|
||||
{
|
||||
/* sometimes---rarely---when the ADC available-byte-count is
|
||||
zero, it's genuine, but usually it's because we're so
|
||||
late that the ADC has overrun its entire kernel buffer. We
|
||||
distinguish between the two by waiting 2 msec and asking again.
|
||||
There should be an error flag we could check instead; look for this
|
||||
someday... */
|
||||
for (dev = 0;dev < linux_nindevs; dev++)
|
||||
if (linux_adcs[dev].d_space == 0)
|
||||
{
|
||||
audio_buf_info ainfo;
|
||||
sys_microsleep(2000);
|
||||
oss_calcspace();
|
||||
if (linux_adcs[dev].d_space != 0) continue;
|
||||
|
||||
/* here's the bad case. Give up and resync. */
|
||||
sys_log_error(ERR_DATALATE);
|
||||
oss_doresync();
|
||||
return (SENDDACS_NO);
|
||||
}
|
||||
/* check for slippage between devices, either because
|
||||
data got lost in the driver from a previous late condition, or
|
||||
because the devices aren't synced. When we're idle, no
|
||||
input device should have more than one buffer readable and
|
||||
no output device should have less than sys_advance_samples-1
|
||||
*/
|
||||
|
||||
for (dev=0; dev < linux_noutdevs; dev++)
|
||||
if (!linux_dacs[dev].d_dropcount &&
|
||||
(linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
|
||||
(sys_advance_samples - 2) *
|
||||
(linux_dacs[dev].d_bytespersamp *
|
||||
linux_dacs[dev].d_nchannels)))
|
||||
goto badsync;
|
||||
for (dev=0; dev < linux_nindevs; dev++)
|
||||
if (linux_adcs[dev].d_space > 3 *
|
||||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
|
||||
linux_adcs[dev].d_bytespersamp))
|
||||
goto badsync;
|
||||
|
||||
/* return zero to tell the scheduler we're idle. */
|
||||
return (SENDDACS_NO);
|
||||
badsync:
|
||||
sys_log_error(ERR_RESYNC);
|
||||
oss_doresync();
|
||||
return (SENDDACS_NO);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* do output */
|
||||
|
||||
timeref = sys_getrealtime();
|
||||
for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
|
||||
{
|
||||
int nchannels = linux_dacs[dev].d_nchannels;
|
||||
if (linux_dacs[dev].d_dropcount)
|
||||
linux_dacs[dev].d_dropcount--;
|
||||
else
|
||||
{
|
||||
if (linux_dacs[dev].d_bytespersamp == 4)
|
||||
{
|
||||
for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
|
||||
DEFDACBLKSIZE*thischan,
|
||||
lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
|
||||
{
|
||||
t_sample f = SCALE32(*fp1);
|
||||
*lp = (f >= 2147483647 ? 2147483647 :
|
||||
(f < -2147483647 ? -2147483647 : f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
|
||||
DEFDACBLKSIZE*thischan,
|
||||
sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
|
||||
{
|
||||
for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
|
||||
{
|
||||
int s = SCALE16(*fp2);
|
||||
if (s > 32767) s = 32767;
|
||||
else if (s < -32767) s = -32767;
|
||||
sp[j] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#define PR_S "%8d"
|
||||
{
|
||||
int nm = 64;
|
||||
int* sp1 = buf;
|
||||
post("dac:");
|
||||
while (nm > 0)
|
||||
{
|
||||
post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S,
|
||||
sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]);
|
||||
nm -= 8;
|
||||
sp1 += 8;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
linux_dacs_write(linux_dacs[dev].d_fd, buf,
|
||||
OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
|
||||
|
||||
#if 0
|
||||
if ((timenow = sys_getrealtime()) - timeref > 200)
|
||||
{
|
||||
post("dacslept %d",sys_getrealtime() - timeref);
|
||||
if (!oss_blockmode)
|
||||
sys_log_error(ERR_DACSLEPT);
|
||||
else rtnval = SENDDACS_SLEPT;
|
||||
}
|
||||
#endif
|
||||
timeref = timenow;
|
||||
}
|
||||
thischan += nchannels;
|
||||
}
|
||||
memset(sys_soundout, 0,
|
||||
sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
|
||||
|
||||
/* do input */
|
||||
|
||||
for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
|
||||
{
|
||||
int nchannels = linux_adcs[dev].d_nchannels;
|
||||
linux_adcs_read(linux_adcs[dev].d_fd, buf,
|
||||
OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
|
||||
|
||||
#if 0
|
||||
if ((timenow = sys_getrealtime()) - timeref > 200)
|
||||
{
|
||||
if (!oss_blockmode)
|
||||
sys_log_error(ERR_ADCSLEPT);
|
||||
else
|
||||
rtnval = SENDDACS_SLEPT;
|
||||
}
|
||||
#endif
|
||||
timeref = timenow;
|
||||
|
||||
if (linux_adcs[dev].d_bytespersamp == 4)
|
||||
{
|
||||
for (i = DEFDACBLKSIZE*nchannels,
|
||||
fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
|
||||
lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
|
||||
{
|
||||
*fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
|
||||
sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
|
||||
{
|
||||
for (j=0;j<sys_inchannels;j++)
|
||||
fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]);
|
||||
}
|
||||
}
|
||||
thischan += nchannels;
|
||||
}
|
||||
if (thischan != sys_inchannels)
|
||||
bug("inchannels");
|
||||
return (rtnval);
|
||||
}
|
||||
|
||||
void oss_listdevs( void)
|
||||
{
|
||||
post("device listing not implemented in OSS yet\n");
|
||||
}
|
||||
|
||||
void oss_getdevs(char *indevlist, int *nindevs,
|
||||
char *outdevlist, int *noutdevs, int *canmulti,
|
||||
int maxndev, int devdescsize)
|
||||
{
|
||||
int i, ndev;
|
||||
*canmulti = 2; /* supports multiple devices */
|
||||
if ((ndev = oss_ndev) > maxndev)
|
||||
ndev = maxndev;
|
||||
for (i = 0; i < ndev; i++)
|
||||
{
|
||||
sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1);
|
||||
sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1);
|
||||
}
|
||||
*nindevs = *noutdevs = ndev;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,293 +0,0 @@
|
|||
/* Copyright (c) 2001 Miller Puckette and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
|
||||
the main way in for Mac OS and, with Michael Casey's help, also into
|
||||
ASIO in Windows. */
|
||||
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "portaudio.h"
|
||||
#include "pablio_pd.h"
|
||||
|
||||
/* LATER try to figure out how to handle default devices in portaudio;
|
||||
the way s_audio.c handles them isn't going to work here. */
|
||||
|
||||
#if defined(MACOSX) || defined(MSW)
|
||||
#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID
|
||||
#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID
|
||||
#endif
|
||||
|
||||
/* public interface declared in m_imp.h */
|
||||
|
||||
/* implementation */
|
||||
static PABLIO_Stream *pa_stream;
|
||||
static int pa_inchans, pa_outchans;
|
||||
static float *pa_soundin, *pa_soundout;
|
||||
|
||||
#define MAX_PA_CHANS 32
|
||||
#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DEFDACBLKSIZE
|
||||
|
||||
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
|
||||
t_sample *soundout, int framesperbuf, int nbuffers,
|
||||
int indeviceno, int outdeviceno)
|
||||
{
|
||||
PaError err;
|
||||
static int initialized;
|
||||
int j, devno, pa_indev = 0, pa_outdev = 0;
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
/* Initialize PortAudio */
|
||||
int err = Pa_Initialize();
|
||||
if ( err != paNoError )
|
||||
{
|
||||
fprintf( stderr,
|
||||
"Error number %d occured initializing portaudio\n",
|
||||
err);
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return (1);
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
/* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
|
||||
if (inchans != 0 && outchans != 0 && inchans != outchans)
|
||||
error("portaudio: number of input and output channels must match");
|
||||
if (inchans > MAX_PA_CHANS)
|
||||
{
|
||||
post("input channels reduced to maximum %d", MAX_PA_CHANS);
|
||||
inchans = MAX_PA_CHANS;
|
||||
}
|
||||
if (outchans > MAX_PA_CHANS)
|
||||
{
|
||||
post("output channels reduced to maximum %d", MAX_PA_CHANS);
|
||||
outchans = MAX_PA_CHANS;
|
||||
}
|
||||
|
||||
if (inchans > 0)
|
||||
{
|
||||
for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
|
||||
{
|
||||
const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
|
||||
if (info->maxInputChannels > 0)
|
||||
{
|
||||
if (devno == indeviceno)
|
||||
{
|
||||
pa_indev = j;
|
||||
break;
|
||||
}
|
||||
devno++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outchans > 0)
|
||||
{
|
||||
for (j = 0, devno = 0; j < Pa_CountDevices(); j++)
|
||||
{
|
||||
const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
|
||||
if (info->maxOutputChannels > 0)
|
||||
{
|
||||
if (devno == outdeviceno)
|
||||
{
|
||||
pa_outdev = j;
|
||||
break;
|
||||
}
|
||||
devno++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sys_verbose)
|
||||
{
|
||||
post("input device %d, channels %d", pa_indev, inchans);
|
||||
post("output device %d, channels %d", pa_outdev, outchans);
|
||||
post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers);
|
||||
}
|
||||
if (inchans && outchans)
|
||||
err = OpenAudioStream( &pa_stream, rate, paFloat32,
|
||||
PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers,
|
||||
pa_indev, pa_outdev);
|
||||
else if (inchans)
|
||||
err = OpenAudioStream( &pa_stream, rate, paFloat32,
|
||||
PABLIO_READ, inchans, framesperbuf, nbuffers,
|
||||
pa_indev, pa_outdev);
|
||||
else if (outchans)
|
||||
err = OpenAudioStream( &pa_stream, rate, paFloat32,
|
||||
PABLIO_WRITE, outchans, framesperbuf, nbuffers,
|
||||
pa_indev, pa_outdev);
|
||||
else err = 0;
|
||||
if ( err != paNoError )
|
||||
{
|
||||
fprintf( stderr, "Error number %d occured opening portaudio stream\n",
|
||||
err);
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
Pa_Terminate();
|
||||
sys_inchannels = sys_outchannels = 0;
|
||||
return (1);
|
||||
}
|
||||
else if (sys_verbose)
|
||||
post("... opened OK.");
|
||||
pa_inchans = inchans;
|
||||
pa_outchans = outchans;
|
||||
pa_soundin = soundin;
|
||||
pa_soundout = soundout;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void pa_close_audio( void)
|
||||
{
|
||||
if (pa_inchans || pa_outchans)
|
||||
CloseAudioStream( pa_stream );
|
||||
pa_inchans = pa_outchans = 0;
|
||||
}
|
||||
|
||||
int pa_send_dacs(void)
|
||||
{
|
||||
float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2;
|
||||
int i, j;
|
||||
double timebefore;
|
||||
|
||||
timebefore = sys_getrealtime();
|
||||
if ((pa_inchans && GetAudioStreamReadable(pa_stream) < DEFDACBLKSIZE) ||
|
||||
(pa_outchans && GetAudioStreamWriteable(pa_stream) < DEFDACBLKSIZE))
|
||||
{
|
||||
if (pa_inchans && pa_outchans)
|
||||
{
|
||||
int synced = 0;
|
||||
while (GetAudioStreamWriteable(pa_stream) > 2*DEFDACBLKSIZE)
|
||||
{
|
||||
for (j = 0; j < pa_outchans; j++)
|
||||
for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
|
||||
fp2 += pa_outchans)
|
||||
{
|
||||
*fp2 = 0;
|
||||
}
|
||||
synced = 1;
|
||||
WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
|
||||
}
|
||||
while (GetAudioStreamReadable(pa_stream) > 2*DEFDACBLKSIZE)
|
||||
{
|
||||
synced = 1;
|
||||
ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
|
||||
}
|
||||
/* if (synced)
|
||||
post("sync"); */
|
||||
}
|
||||
return (SENDDACS_NO);
|
||||
}
|
||||
if (pa_inchans)
|
||||
{
|
||||
ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
|
||||
for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE)
|
||||
for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
|
||||
fp2 += pa_inchans)
|
||||
{
|
||||
fp1[i] = *fp2;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
static int nread;
|
||||
if (nread == 0)
|
||||
{
|
||||
post("it's %f %f %f %f",
|
||||
pa_soundin[0], pa_soundin[1], pa_soundin[2], pa_soundin[3]);
|
||||
nread = 1000;
|
||||
}
|
||||
nread--;
|
||||
}
|
||||
#endif
|
||||
if (pa_outchans)
|
||||
{
|
||||
for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++,
|
||||
fp1 += DEFDACBLKSIZE)
|
||||
for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
|
||||
fp2 += pa_outchans)
|
||||
{
|
||||
*fp2 = fp1[i];
|
||||
fp1[i] = 0;
|
||||
}
|
||||
WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
|
||||
}
|
||||
|
||||
if (sys_getrealtime() > timebefore + 0.002)
|
||||
{
|
||||
/* post("slept"); */
|
||||
return (SENDDACS_SLEPT);
|
||||
}
|
||||
else return (SENDDACS_YES);
|
||||
}
|
||||
|
||||
|
||||
void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */
|
||||
{
|
||||
int i,j;
|
||||
int numDevices;
|
||||
const PaDeviceInfo *pdi;
|
||||
PaError err;
|
||||
Pa_Initialize();
|
||||
numDevices = Pa_CountDevices();
|
||||
if( numDevices < 0 )
|
||||
{
|
||||
fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
|
||||
err = numDevices;
|
||||
goto error;
|
||||
}
|
||||
fprintf(stderr, "Audio Devices:\n");
|
||||
for( i=0; i<numDevices; i++ )
|
||||
{
|
||||
pdi = Pa_GetDeviceInfo( i );
|
||||
fprintf(stderr, "device %d:", i+1 );
|
||||
fprintf(stderr, " %s;", pdi->name );
|
||||
fprintf(stderr, "%d inputs, ", pdi->maxInputChannels );
|
||||
fprintf(stderr, "%d outputs", pdi->maxOutputChannels );
|
||||
if ( i == Pa_GetDefaultInputDevice() )
|
||||
fprintf(stderr, " (Default Input)");
|
||||
if ( i == Pa_GetDefaultOutputDevice() )
|
||||
fprintf(stderr, " (Default Output)");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
return;
|
||||
|
||||
error:
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
|
||||
}
|
||||
|
||||
/* scanning for devices */
|
||||
void pa_getdevs(char *indevlist, int *nindevs,
|
||||
char *outdevlist, int *noutdevs, int *canmulti,
|
||||
int maxndev, int devdescsize)
|
||||
{
|
||||
int i, nin = 0, nout = 0, ndev;
|
||||
*canmulti = 1; /* one dev each for input and output */
|
||||
|
||||
Pa_Initialize();
|
||||
ndev = Pa_CountDevices();
|
||||
for (i = 0; i < ndev; i++)
|
||||
{
|
||||
const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
|
||||
if (pdi->maxInputChannels > 0 && nin < maxndev)
|
||||
{
|
||||
strcpy(indevlist + nin * devdescsize, pdi->name);
|
||||
nin++;
|
||||
}
|
||||
if (pdi->maxOutputChannels > 0 && nout < maxndev)
|
||||
{
|
||||
strcpy(outdevlist + nout * devdescsize, pdi->name);
|
||||
nout++;
|
||||
}
|
||||
}
|
||||
*nindevs = nin;
|
||||
*noutdevs = nout;
|
||||
}
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/* In MSW, this is all there is to pd; the rest sits in a "pdlib" dll so
|
||||
that externs can link back to functions defined in pd. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int sys_main(int argc, char **argv);
|
||||
|
||||
/* WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler(
|
||||
ULONG FirstHandler,
|
||||
PVECTORED_EXCEPTION_HANDLER VectoredHandler ); */
|
||||
|
||||
#ifdef MSW
|
||||
#if 0
|
||||
#incldue "winbase.h"
|
||||
|
||||
LONG NTAPI VectoredExceptionHandler(void *PEXCEPTION_POINTERS)
|
||||
{
|
||||
fprintf(stderr, "caught exception\n");
|
||||
return(EXCEPTION_CONTINUE_SEARCH);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Pd entry point\n");
|
||||
AddVectoredExceptionHandler(
|
||||
ULONG FirstHandler,
|
||||
PVECTORED_EXCEPTION_HANDLER VectoredHandler );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
__try
|
||||
{
|
||||
sys_main(argc, argv);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
printf("caught an exception; stopping\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else /* not MSW */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return (sys_main(argc, argv));
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,839 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* IOhannes :
|
||||
* hacked the code to add advanced multidevice-support
|
||||
* 1311:forum::für::umläute:2001
|
||||
*/
|
||||
|
||||
char pd_version[] = "Pd version 0.37.4\n";
|
||||
char pd_compiletime[] = __TIME__;
|
||||
char pd_compiledate[] = __DATE__;
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "m_imp.h"
|
||||
#include "s_stuff.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef MSW
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
void pd_init(void);
|
||||
int sys_argparse(int argc, char **argv);
|
||||
void sys_findprogdir(char *progname);
|
||||
int sys_startgui(const char *guipath);
|
||||
int sys_rcfile(void);
|
||||
int m_scheduler(void);
|
||||
void sys_addhelppath(char *p);
|
||||
void alsa_adddev(char *name);
|
||||
|
||||
int sys_debuglevel;
|
||||
int sys_verbose;
|
||||
int sys_noloadbang;
|
||||
int sys_nogui;
|
||||
int sys_stdin = 0;
|
||||
char *sys_guicmd;
|
||||
t_symbol *sys_libdir;
|
||||
static t_symbol *sys_guidir;
|
||||
static t_namelist *sys_externlist;
|
||||
static t_namelist *sys_openlist;
|
||||
static t_namelist *sys_messagelist;
|
||||
static int sys_version;
|
||||
int sys_oldtclversion; /* hack to warn g_rtext.c about old text sel */
|
||||
|
||||
int sys_nmidiout = 1;
|
||||
#ifdef MSW
|
||||
int sys_nmidiin = 0;
|
||||
#else
|
||||
int sys_nmidiin = 1;
|
||||
#endif
|
||||
int sys_midiindevlist[MAXMIDIINDEV] = {1};
|
||||
int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
|
||||
|
||||
static int sys_main_srate = DEFAULTSRATE;
|
||||
static int sys_main_advance = DEFAULTADVANCE;
|
||||
|
||||
/* IOhannes { */
|
||||
|
||||
/* here the "-1" counts signify that the corresponding vector hasn't been
|
||||
specified in command line arguments; sys_open_audio will detect this
|
||||
and fill things in. */
|
||||
int sys_nsoundin = -1;
|
||||
int sys_nsoundout = -1;
|
||||
int sys_soundindevlist[MAXAUDIOINDEV];
|
||||
int sys_soundoutdevlist[MAXAUDIOOUTDEV];
|
||||
|
||||
int sys_nchin = -1;
|
||||
int sys_nchout = -1;
|
||||
int sys_chinlist[MAXAUDIOINDEV];
|
||||
int sys_choutlist[MAXAUDIOOUTDEV];
|
||||
/* } IOhannes */
|
||||
|
||||
|
||||
typedef struct _fontinfo
|
||||
{
|
||||
int fi_fontsize;
|
||||
int fi_maxwidth;
|
||||
int fi_maxheight;
|
||||
int fi_hostfontsize;
|
||||
int fi_width;
|
||||
int fi_height;
|
||||
} t_fontinfo;
|
||||
|
||||
/* these give the nominal point size and maximum height of the characters
|
||||
in the six fonts. */
|
||||
|
||||
static t_fontinfo sys_fontlist[] = {
|
||||
{8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
|
||||
{16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
|
||||
#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
|
||||
|
||||
/* here are the actual font size structs on msp's systems:
|
||||
MSW:
|
||||
font 8 5 9 8 5 11
|
||||
font 10 7 13 10 6 13
|
||||
font 12 9 16 14 8 16
|
||||
font 16 10 20 16 10 18
|
||||
font 24 15 25 16 10 18
|
||||
font 36 25 42 36 22 41
|
||||
|
||||
linux:
|
||||
font 8 5 9 8 5 9
|
||||
font 10 7 13 12 7 13
|
||||
font 12 9 16 14 9 15
|
||||
font 16 10 20 16 10 19
|
||||
font 24 15 25 24 15 24
|
||||
font 36 25 42 36 22 41
|
||||
*/
|
||||
|
||||
static t_fontinfo *sys_findfont(int fontsize)
|
||||
{
|
||||
unsigned int i;
|
||||
t_fontinfo *fi;
|
||||
for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
|
||||
if (fontsize < fi[1].fi_fontsize) return (fi);
|
||||
return (sys_fontlist + (NFONT-1));
|
||||
}
|
||||
|
||||
int sys_nearestfontsize(int fontsize)
|
||||
{
|
||||
return (sys_findfont(fontsize)->fi_fontsize);
|
||||
}
|
||||
|
||||
int sys_hostfontsize(int fontsize)
|
||||
{
|
||||
return (sys_findfont(fontsize)->fi_hostfontsize);
|
||||
}
|
||||
|
||||
int sys_fontwidth(int fontsize)
|
||||
{
|
||||
return (sys_findfont(fontsize)->fi_width);
|
||||
}
|
||||
|
||||
int sys_fontheight(int fontsize)
|
||||
{
|
||||
return (sys_findfont(fontsize)->fi_height);
|
||||
}
|
||||
|
||||
int sys_defaultfont;
|
||||
#ifdef MSW
|
||||
#define DEFAULTFONT 12
|
||||
#else
|
||||
#define DEFAULTFONT 10
|
||||
#endif
|
||||
|
||||
static void openit(const char *dirname, const char *filename)
|
||||
{
|
||||
char dirbuf[MAXPDSTRING], *nameptr;
|
||||
int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
|
||||
MAXPDSTRING, 0);
|
||||
if (fd)
|
||||
{
|
||||
close (fd);
|
||||
glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
|
||||
}
|
||||
else
|
||||
error("%s: can't open", filename);
|
||||
}
|
||||
|
||||
#define NHOSTFONT 7
|
||||
|
||||
/* this is called from the gui process. The first argument is the cwd, and
|
||||
succeeding args give the widths and heights of known fonts. We wait until
|
||||
these are known to open files and send messages specified on the command line.
|
||||
We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
|
||||
from; for instance we could be some kind of RT embedded system. However, to
|
||||
really make this make sense we would have to implement
|
||||
open(), read(), etc, calls to be served somehow from the GUI too. */
|
||||
|
||||
void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
|
||||
t_namelist *nl;
|
||||
unsigned int i, j;
|
||||
if (argc != 2 + 3 * NHOSTFONT) bug("glob_initfromgui");
|
||||
for (i = 0; i < NFONT; i++)
|
||||
{
|
||||
int wantheight = sys_fontlist[i].fi_maxheight;
|
||||
for (j = 0; j < NHOSTFONT-1; j++)
|
||||
{
|
||||
if (atom_getintarg(3 * (j + 1) + 3, argc, argv) > wantheight)
|
||||
break;
|
||||
}
|
||||
/* j is now the "real" font index for the desired font index i. */
|
||||
sys_fontlist[i].fi_hostfontsize = atom_getintarg(3 * j + 1, argc, argv);
|
||||
sys_fontlist[i].fi_width = atom_getintarg(3 * j + 2, argc, argv);
|
||||
sys_fontlist[i].fi_height = atom_getintarg(3 * j + 3, argc, argv);
|
||||
}
|
||||
#if 0
|
||||
for (i = 0; i < 6; i++)
|
||||
fprintf(stderr, "font %d %d %d %d %d\n",
|
||||
sys_fontlist[i].fi_fontsize,
|
||||
sys_fontlist[i].fi_maxheight,
|
||||
sys_fontlist[i].fi_hostfontsize,
|
||||
sys_fontlist[i].fi_width,
|
||||
sys_fontlist[i].fi_height);
|
||||
#endif
|
||||
/* load dynamic libraries specified with "-lib" args */
|
||||
for (nl = sys_externlist; nl; nl = nl->nl_next)
|
||||
if (!sys_load_lib(cwd, nl->nl_string))
|
||||
post("%s: can't load library", nl->nl_string);
|
||||
namelist_free(sys_externlist);
|
||||
sys_externlist = 0;
|
||||
/* open patches specifies with "-open" args */
|
||||
for (nl = sys_openlist; nl; nl = nl->nl_next)
|
||||
openit(cwd, nl->nl_string);
|
||||
namelist_free(sys_openlist);
|
||||
sys_openlist = 0;
|
||||
/* send messages specified with "-send" args */
|
||||
for (nl = sys_messagelist; nl; nl = nl->nl_next)
|
||||
{
|
||||
t_binbuf *b = binbuf_new();
|
||||
binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
|
||||
binbuf_eval(b, 0, 0, 0);
|
||||
binbuf_free(b);
|
||||
}
|
||||
namelist_free(sys_messagelist);
|
||||
sys_messagelist = 0;
|
||||
sys_oldtclversion = atom_getfloatarg(1 + 3 * NHOSTFONT, argc, argv);
|
||||
}
|
||||
|
||||
static void sys_afterargparse(void);
|
||||
|
||||
/* this is called from main() in s_entry.c */
|
||||
int sys_main(int argc, char **argv)
|
||||
{
|
||||
#ifdef PD_DEBUG
|
||||
fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
|
||||
#endif
|
||||
pd_init();
|
||||
sys_findprogdir(argv[0]); /* set sys_progname, guipath */
|
||||
#ifdef UNIX
|
||||
sys_rcfile(); /* parse the startup file */
|
||||
#endif
|
||||
if (sys_argparse(argc, argv)) /* parse cmd line */
|
||||
return (1);
|
||||
sys_afterargparse(); /* post-argparse settings */
|
||||
if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
|
||||
pd_version, pd_compiletime, pd_compiledate);
|
||||
if (sys_version) /* if we were just asked our version, exit here. */
|
||||
return (0);
|
||||
if (sys_startgui(sys_guidir->s_name)) /* start the gui */
|
||||
return(1);
|
||||
/* open audio and MIDI */
|
||||
sys_open_midi(sys_nmidiin, sys_midiindevlist,
|
||||
sys_nmidiout, sys_midioutdevlist);
|
||||
sys_open_audio(sys_nsoundin, sys_soundindevlist, sys_nchin, sys_chinlist,
|
||||
sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist,
|
||||
sys_main_srate, sys_main_advance, 1);
|
||||
/* run scheduler until it quits */
|
||||
|
||||
return (m_scheduler_pda());
|
||||
return (m_scheduler());
|
||||
}
|
||||
|
||||
static char *(usagemessage[]) = {
|
||||
"usage: pd [-flags] [file]...\n",
|
||||
"\naudio configuration flags:\n",
|
||||
"-r <n> -- specify sample rate\n",
|
||||
"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third\n",
|
||||
"-audiooutdev ... -- audio out devices (same)\n",
|
||||
"-audiodev ... -- specify input and output together\n",
|
||||
"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")\n",
|
||||
"-outchannels ... -- number of audio out channels (same)\n",
|
||||
"-channels ... -- specify both input and output channels\n",
|
||||
"-audiobuf <n> -- specify size of audio buffer in msec\n",
|
||||
"-blocksize <n> -- specify audio I/O block size in sample frames\n",
|
||||
"-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
|
||||
"-nodac -- suppress audio output\n",
|
||||
"-noadc -- suppress audio input\n",
|
||||
"-noaudio -- suppress audio input and output (-nosound is synonym) \n",
|
||||
"-listdev -- list audio and MIDI devices\n",
|
||||
|
||||
#ifdef USEAPI_OSS
|
||||
"-oss -- use OSS audio API\n",
|
||||
"-32bit ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
|
||||
#endif
|
||||
|
||||
#ifdef USEAPI_ALSA
|
||||
"-alsa -- use ALSA audio API\n",
|
||||
"-alsaadd <name> -- add an ALSA device name to list\n",
|
||||
"-alsadev <n> ----- obsolete: use -audiodev\n",
|
||||
#endif
|
||||
|
||||
#ifdef USEAPI_JACK
|
||||
"-jack -- use JACK audio API\n",
|
||||
#endif
|
||||
|
||||
#ifdef USEAPI_PORTAUDIO
|
||||
#ifdef MSW
|
||||
"-asio -- use ASIO audio driver (via Portaudio)\n",
|
||||
"-pa -- synonym for -asio\n",
|
||||
#else
|
||||
"-pa -- use Portaudio API\n",
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USEAPI_MMIO
|
||||
"-mmio -- use MMIO audio API (default for Windows)\n",
|
||||
#endif
|
||||
" (default audio API for this platform: ", API_DEFSTRING, ")\n\n",
|
||||
|
||||
"\nMIDI configuration flags:\n",
|
||||
"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
|
||||
"-midioutdev ... -- midi out device list, same format\n",
|
||||
"-mididev ... -- specify -midioutdev and -midiindev together\n",
|
||||
"-nomidiin -- suppress MIDI input\n",
|
||||
"-nomidiout -- suppress MIDI output\n",
|
||||
"-nomidi -- suppress MIDI input and output\n",
|
||||
|
||||
"\nother flags:\n",
|
||||
"-path <path> -- add to file search path\n",
|
||||
"-helppath <path> -- add to help file search path\n",
|
||||
"-open <file> -- open file(s) on startup\n",
|
||||
"-lib <file> -- load object library(s)\n",
|
||||
"-font <n> -- specify default font size in points\n",
|
||||
"-verbose -- extra printout on startup and when searching for files\n",
|
||||
"-version -- don't run Pd; just print out which version it is \n",
|
||||
"-d <n> -- specify debug level\n",
|
||||
"-noloadbang -- suppress all loadbangs\n",
|
||||
"-nogui -- suppress starting the GUI\n",
|
||||
"-stdin -- scan stdin for keypresses\n",
|
||||
"-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
|
||||
"-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
|
||||
#ifdef UNIX
|
||||
"-rt or -realtime -- use real-time priority\n",
|
||||
"-nrt -- don't use real-time priority\n",
|
||||
#endif
|
||||
};
|
||||
|
||||
static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
|
||||
{
|
||||
int n = 0;
|
||||
while (n < max)
|
||||
{
|
||||
if (!*str) break;
|
||||
else
|
||||
{
|
||||
char *endp;
|
||||
vecp[n] = strtol(str, &endp, 10);
|
||||
if (endp == str)
|
||||
break;
|
||||
n++;
|
||||
if (!endp)
|
||||
break;
|
||||
str = endp + 1;
|
||||
}
|
||||
}
|
||||
*np = n;
|
||||
}
|
||||
|
||||
static int sys_getmultidevchannels(int n, int *devlist)
|
||||
{
|
||||
int sum = 0;
|
||||
if (n<0)return(-1);
|
||||
if (n==0)return 0;
|
||||
while(n--)sum+=*devlist++;
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
/* this routine tries to figure out where to find the auxilliary files
|
||||
Pd will need to run. This is either done by looking at the command line
|
||||
invokation for Pd, or if that fails, by consulting the variable
|
||||
INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
|
||||
void sys_findprogdir(char *progname)
|
||||
{
|
||||
char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
|
||||
char *lastslash;
|
||||
#ifdef UNIX
|
||||
struct stat statbuf;
|
||||
#endif
|
||||
|
||||
/* find out by what string Pd was invoked; put answer in "sbuf". */
|
||||
#ifdef MSW
|
||||
GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
|
||||
sbuf2[MAXPDSTRING-1] = 0;
|
||||
sys_unbashfilename(sbuf2, sbuf);
|
||||
#endif /* MSW */
|
||||
#ifdef UNIX
|
||||
strncpy(sbuf, progname, MAXPDSTRING);
|
||||
sbuf[MAXPDSTRING-1] = 0;
|
||||
#endif
|
||||
lastslash = strrchr(sbuf, '/');
|
||||
if (lastslash)
|
||||
{
|
||||
/* bash last slash to zero so that sbuf is directory pd was in,
|
||||
e.g., ~/pd/bin */
|
||||
*lastslash = 0;
|
||||
/* go back to the parent from there, e.g., ~/pd */
|
||||
lastslash = strrchr(sbuf, '/');
|
||||
if (lastslash)
|
||||
{
|
||||
strncpy(sbuf2, sbuf, lastslash-sbuf);
|
||||
sbuf2[lastslash-sbuf] = 0;
|
||||
}
|
||||
else strcpy(sbuf2, "..");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no slashes found. Try INSTALL_PREFIX. */
|
||||
#ifdef INSTALL_PREFIX
|
||||
strcpy(sbuf2, INSTALL_PREFIX);
|
||||
#else
|
||||
strcpy(sbuf2, ".");
|
||||
#endif
|
||||
}
|
||||
/* now we believe sbuf2 holds the parent directory of the directory
|
||||
pd was found in. We now want to infer the "lib" directory and the
|
||||
"gui" directory. In "simple" UNIX installations, the layout is
|
||||
.../bin/pd
|
||||
.../bin/pd-gui
|
||||
.../doc
|
||||
and in "complicated" UNIX installations, it's:
|
||||
.../bin/pd
|
||||
.../lib/pd/bin/pd-gui
|
||||
.../lib/pd/doc
|
||||
To decide which, we stat .../lib/pd; if that exists, we assume it's
|
||||
the complicated layout. In MSW, it's the "simple" layout, but
|
||||
the gui program is straight wish80:
|
||||
.../bin/pd
|
||||
.../bin/wish80.exe
|
||||
.../doc
|
||||
*/
|
||||
#ifdef UNIX
|
||||
strncpy(sbuf, sbuf2, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/lib/pd");
|
||||
if (stat(sbuf, &statbuf) >= 0)
|
||||
{
|
||||
/* complicated layout: lib dir is the one we just stat-ed above */
|
||||
sys_libdir = gensym(sbuf);
|
||||
/* gui lives in .../lib/pd/bin */
|
||||
strncpy(sbuf, sbuf2, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/lib/pd/bin");
|
||||
sys_guidir = gensym(sbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* simple layout: lib dir is the parent */
|
||||
sys_libdir = gensym(sbuf2);
|
||||
/* gui lives in .../bin */
|
||||
strncpy(sbuf, sbuf2, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/bin");
|
||||
sys_guidir = gensym(sbuf);
|
||||
}
|
||||
#endif
|
||||
#ifdef MSW
|
||||
sys_libdir = gensym(sbuf2);
|
||||
sys_guidir = &s_; /* in MSW the guipath just depends on the libdir */
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MSW
|
||||
static int sys_mmio = 1;
|
||||
#else
|
||||
static int sys_mmio = 0;
|
||||
#endif
|
||||
|
||||
int sys_argparse(int argc, char **argv)
|
||||
{
|
||||
char sbuf[MAXPDSTRING];
|
||||
int i;
|
||||
argc--; argv++;
|
||||
while ((argc > 0) && **argv == '-')
|
||||
{
|
||||
if (!strcmp(*argv, "-r") && argc > 1 &&
|
||||
sscanf(argv[1], "%d", &sys_main_srate) >= 1)
|
||||
{
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-inchannels"))
|
||||
{ /* IOhannes */
|
||||
sys_parsedevlist(&sys_nchin,
|
||||
sys_chinlist, MAXAUDIOINDEV, argv[1]);
|
||||
|
||||
if (!sys_nchin)
|
||||
goto usage;
|
||||
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-outchannels"))
|
||||
{ /* IOhannes */
|
||||
sys_parsedevlist(&sys_nchout, sys_choutlist,
|
||||
MAXAUDIOOUTDEV, argv[1]);
|
||||
|
||||
if (!sys_nchout)
|
||||
goto usage;
|
||||
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-channels"))
|
||||
{
|
||||
sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
|
||||
argv[1]);
|
||||
sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV,
|
||||
argv[1]);
|
||||
|
||||
if (!sys_nchout)
|
||||
goto usage;
|
||||
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf"))
|
||||
{
|
||||
sys_main_advance = atoi(argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-blocksize"))
|
||||
{
|
||||
sys_setblocksize(atoi(argv[1]));
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-sleepgrain"))
|
||||
{
|
||||
sys_sleepgrain = 1000 * atoi(argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nodac"))
|
||||
{ /* IOhannes */
|
||||
sys_nsoundout=0;
|
||||
sys_nchout = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-noadc"))
|
||||
{ /* IOhannes */
|
||||
sys_nsoundin=0;
|
||||
sys_nchin = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
|
||||
{ /* IOhannes */
|
||||
sys_nsoundin=sys_nsoundout = 0;
|
||||
sys_nchin = sys_nchout = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
#ifdef USEAPI_OSS
|
||||
else if (!strcmp(*argv, "-oss"))
|
||||
{
|
||||
sys_set_audio_api(API_OSS);
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-32bit"))
|
||||
{
|
||||
sys_set_audio_api(API_OSS);
|
||||
oss_set32bit();
|
||||
argc--; argv++;
|
||||
}
|
||||
#endif
|
||||
#ifdef USEAPI_ALSA
|
||||
else if (!strcmp(*argv, "-alsa"))
|
||||
{
|
||||
sys_set_audio_api(API_ALSA);
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-alsaadd"))
|
||||
{
|
||||
if (argc > 1)
|
||||
alsa_adddev(argv[1]);
|
||||
else goto usage;
|
||||
argc -= 2; argv +=2;
|
||||
}
|
||||
/* obsolete flag for setting ALSA device number or name */
|
||||
else if (!strcmp(*argv, "-alsadev"))
|
||||
{
|
||||
int devno = 0;
|
||||
if (argv[1][0] >= '1' && argv[1][0] <= '9')
|
||||
devno = 1 + 2 * (atoi(argv[1]) - 1);
|
||||
else if (!strncmp(argv[1], "hw:", 3))
|
||||
devno = 1 + 2 * atoi(argv[1]+3);
|
||||
else if (!strncmp(argv[1], "plughw:", 7))
|
||||
devno = 2 + 2 * atoi(argv[1]+7);
|
||||
else goto usage;
|
||||
sys_nsoundin = sys_nsoundout = 1;
|
||||
sys_soundindevlist[0] = sys_soundoutdevlist[0] = devno;
|
||||
sys_set_audio_api(API_ALSA);
|
||||
argc -= 2; argv +=2;
|
||||
}
|
||||
#endif
|
||||
#ifdef USEAPI_JACK
|
||||
else if (!strcmp(*argv, "-jack"))
|
||||
{
|
||||
sys_set_audio_api(API_JACK);
|
||||
argc--; argv++;
|
||||
}
|
||||
#endif
|
||||
#ifdef USEAPI_PORTAUDIO
|
||||
else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")
|
||||
#ifdef MSW
|
||||
|| !strcmp(*argv, "-asio")
|
||||
#endif
|
||||
)
|
||||
{
|
||||
sys_set_audio_api(API_PORTAUDIO);
|
||||
sys_mmio = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
#endif
|
||||
#ifdef USEAPI_MMIO
|
||||
else if (!strcmp(*argv, "-mmio"))
|
||||
{
|
||||
sys_set_audio_api(API_MMIO);
|
||||
sys_mmio = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(*argv, "-nomidiin"))
|
||||
{
|
||||
sys_nmidiin = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nomidiout"))
|
||||
{
|
||||
sys_nmidiout = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nomidi"))
|
||||
{
|
||||
sys_nmidiin = sys_nmidiout = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-midiindev"))
|
||||
{
|
||||
sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
|
||||
argv[1]);
|
||||
if (!sys_nmidiin)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-midioutdev"))
|
||||
{
|
||||
sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
|
||||
argv[1]);
|
||||
if (!sys_nmidiout)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-mididev"))
|
||||
{
|
||||
sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
|
||||
argv[1]);
|
||||
sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
|
||||
argv[1]);
|
||||
if (!sys_nmidiout)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-path"))
|
||||
{
|
||||
sys_addpath(argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-helppath"))
|
||||
{
|
||||
sys_addhelppath(argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-open") && argc > 1)
|
||||
{
|
||||
sys_openlist = namelist_append(sys_openlist, argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-lib") && argc > 1)
|
||||
{
|
||||
sys_externlist = namelist_append(sys_externlist, argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-font") && argc > 1)
|
||||
{
|
||||
sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-verbose"))
|
||||
{
|
||||
sys_verbose = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-version"))
|
||||
{
|
||||
sys_version = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-d") && argc > 1 &&
|
||||
sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
|
||||
{
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-noloadbang"))
|
||||
{
|
||||
sys_noloadbang = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nogui"))
|
||||
{
|
||||
sys_nogui = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-stdin"))
|
||||
{
|
||||
sys_stdin = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-guicmd") && argc > 1)
|
||||
{
|
||||
sys_guicmd = argv[1];
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-send") && argc > 1)
|
||||
{
|
||||
sys_messagelist = namelist_append(sys_messagelist, argv[1]);
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-listdev"))
|
||||
{
|
||||
sys_listdevs();
|
||||
argc--; argv++;
|
||||
}
|
||||
#ifdef UNIX
|
||||
else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
|
||||
{
|
||||
sys_hipriority = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp(*argv, "-nrt"))
|
||||
{
|
||||
sys_hipriority = 0;
|
||||
argc--; argv++;
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(*argv, "-soundindev") ||
|
||||
!strcmp(*argv, "-audioindev"))
|
||||
{ /* IOhannes */
|
||||
sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
|
||||
MAXAUDIOINDEV, argv[1]);
|
||||
if (!sys_nsoundin)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-soundoutdev") ||
|
||||
!strcmp(*argv, "-audiooutdev"))
|
||||
{ /* IOhannes */
|
||||
sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
|
||||
MAXAUDIOOUTDEV, argv[1]);
|
||||
if (!sys_nsoundout)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
|
||||
{
|
||||
sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
|
||||
MAXAUDIOINDEV, argv[1]);
|
||||
sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
|
||||
MAXAUDIOOUTDEV, argv[1]);
|
||||
if (!sys_nsoundout)
|
||||
goto usage;
|
||||
argc -= 2; argv += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i;
|
||||
usage:
|
||||
for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
|
||||
fprintf(stderr, "%s", usagemessage[i]);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
if (!sys_defaultfont)
|
||||
sys_defaultfont = DEFAULTFONT;
|
||||
for (; argc > 0; argc--, argv++)
|
||||
sys_openlist = namelist_append(sys_openlist, *argv);
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int sys_getblksize(void)
|
||||
{
|
||||
return (DEFDACBLKSIZE);
|
||||
}
|
||||
|
||||
/* stuff to do, once, after calling sys_argparse() -- which may itself
|
||||
be called twice because of the .pdrc hack. */
|
||||
static void sys_afterargparse(void)
|
||||
{
|
||||
char sbuf[MAXPDSTRING];
|
||||
int i;
|
||||
/* add "extra" library to path */
|
||||
strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/extra");
|
||||
sys_addpath(sbuf);
|
||||
strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/intern");
|
||||
sys_addpath(sbuf);
|
||||
/* add "doc/5.reference" library to helppath */
|
||||
strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
|
||||
sbuf[MAXPDSTRING-30] = 0;
|
||||
strcat(sbuf, "/doc/5.reference");
|
||||
sys_addhelppath(sbuf);
|
||||
/* correct to make audio and MIDI device lists zero based. On
|
||||
MMIO, however, "1" really means the second device (the first one
|
||||
is "mapper" which is was not included when the command args were
|
||||
set up, so we leave it that way for compatibility. */
|
||||
if (!sys_mmio)
|
||||
{
|
||||
for (i = 0; i < sys_nsoundin; i++)
|
||||
sys_soundindevlist[i]--;
|
||||
for (i = 0; i < sys_nsoundout; i++)
|
||||
sys_soundoutdevlist[i]--;
|
||||
}
|
||||
for (i = 0; i < sys_nmidiin; i++)
|
||||
sys_midiindevlist[i]--;
|
||||
for (i = 0; i < sys_nmidiout; i++)
|
||||
sys_midioutdevlist[i]--;
|
||||
}
|
||||
|
||||
static void sys_addreferencepath(void)
|
||||
{
|
||||
char sbuf[MAXPDSTRING];
|
||||
}
|
||||
|
||||
|
|
@ -1,642 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* Clock functions (which should move, but where?) and MIDI queueing */
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include "m_imp.h"
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_BSTRING_H
|
||||
#include <bstring.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MSW
|
||||
#include <winsock.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <wtypes.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct _midiqelem
|
||||
{
|
||||
double q_time;
|
||||
int q_portno;
|
||||
unsigned char q_onebyte;
|
||||
unsigned char q_byte1;
|
||||
unsigned char q_byte2;
|
||||
unsigned char q_byte3;
|
||||
} t_midiqelem;
|
||||
|
||||
#define MIDIQSIZE 1024
|
||||
|
||||
t_midiqelem midi_outqueue[MIDIQSIZE];
|
||||
int midi_outhead, midi_outtail;
|
||||
t_midiqelem midi_inqueue[MIDIQSIZE];
|
||||
int midi_inhead, midi_intail;
|
||||
static double sys_midiinittime;
|
||||
|
||||
/* this is our current estimate for at what "system" real time the
|
||||
current logical time's output should occur. */
|
||||
static double sys_dactimeminusrealtime;
|
||||
/* same for input, should be schduler advance earlier. */
|
||||
static double sys_adctimeminusrealtime;
|
||||
|
||||
static double sys_newdactimeminusrealtime = -1e20;
|
||||
static double sys_newadctimeminusrealtime = -1e20;
|
||||
static double sys_whenupdate;
|
||||
|
||||
void sys_initmidiqueue( void)
|
||||
{
|
||||
sys_midiinittime = clock_getlogicaltime();
|
||||
sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
|
||||
}
|
||||
|
||||
/* this is called from the OS dependent code from time to time when we
|
||||
think we know the delay (outbuftime) in seconds, at which the last-output
|
||||
audio sample will go out the door. */
|
||||
void sys_setmiditimediff(double inbuftime, double outbuftime)
|
||||
{
|
||||
double dactimeminusrealtime =
|
||||
.001 * clock_gettimesince(sys_midiinittime)
|
||||
- outbuftime - sys_getrealtime();
|
||||
double adctimeminusrealtime =
|
||||
.001 * clock_gettimesince(sys_midiinittime)
|
||||
+ inbuftime - sys_getrealtime();
|
||||
if (dactimeminusrealtime > sys_newdactimeminusrealtime)
|
||||
sys_newdactimeminusrealtime = dactimeminusrealtime;
|
||||
if (adctimeminusrealtime > sys_newadctimeminusrealtime)
|
||||
sys_newadctimeminusrealtime = adctimeminusrealtime;
|
||||
if (sys_getrealtime() > sys_whenupdate)
|
||||
{
|
||||
sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
|
||||
sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
|
||||
sys_newdactimeminusrealtime = -1e20;
|
||||
sys_newadctimeminusrealtime = -1e20;
|
||||
sys_whenupdate = sys_getrealtime() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the logical time of the DAC sample we believe is currently
|
||||
going out, based on how much "system time" has elapsed since the
|
||||
last time sys_setmiditimediff got called. */
|
||||
static double sys_getmidioutrealtime( void)
|
||||
{
|
||||
return (sys_getrealtime() + sys_dactimeminusrealtime);
|
||||
}
|
||||
|
||||
static double sys_getmidiinrealtime( void)
|
||||
{
|
||||
return (sys_getrealtime() + sys_adctimeminusrealtime);
|
||||
}
|
||||
|
||||
static void sys_putnext( void)
|
||||
{
|
||||
int portno = midi_outqueue[midi_outtail].q_portno;
|
||||
if (midi_outqueue[midi_outtail].q_onebyte)
|
||||
sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
|
||||
else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
|
||||
midi_outqueue[midi_outtail].q_byte2,
|
||||
midi_outqueue[midi_outtail].q_byte3);
|
||||
midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
|
||||
}
|
||||
|
||||
/* #define TEST_DEJITTER */
|
||||
|
||||
void sys_pollmidioutqueue( void)
|
||||
{
|
||||
#ifdef TEST_DEJITTER
|
||||
static int db = 0;
|
||||
#endif
|
||||
double midirealtime = sys_getmidioutrealtime();
|
||||
#ifdef TEST_DEJITTER
|
||||
if (midi_outhead == midi_outtail)
|
||||
db = 0;
|
||||
#endif
|
||||
while (midi_outhead != midi_outtail)
|
||||
{
|
||||
#ifdef TEST_DEJITTER
|
||||
if (!db)
|
||||
{
|
||||
post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
|
||||
(midi_outqueue[midi_outtail].q_time - midirealtime),
|
||||
midirealtime, .001 * clock_gettimesince(sys_midiinittime),
|
||||
sys_getrealtime(), sys_dactimeminusrealtime);
|
||||
db = 1;
|
||||
}
|
||||
#endif
|
||||
if (midi_outqueue[midi_outtail].q_time <= midirealtime)
|
||||
sys_putnext();
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
|
||||
{
|
||||
t_midiqelem *midiqelem;
|
||||
int newhead = midi_outhead +1;
|
||||
if (newhead == MIDIQSIZE)
|
||||
newhead = 0;
|
||||
/* if FIFO is full flush an element to make room */
|
||||
if (newhead == midi_outtail)
|
||||
sys_putnext();
|
||||
midi_outqueue[midi_outhead].q_portno = portno;
|
||||
midi_outqueue[midi_outhead].q_onebyte = onebyte;
|
||||
midi_outqueue[midi_outhead].q_byte1 = a;
|
||||
midi_outqueue[midi_outhead].q_byte2 = b;
|
||||
midi_outqueue[midi_outhead].q_byte3 = c;
|
||||
midi_outqueue[midi_outhead].q_time =
|
||||
.001 * clock_gettimesince(sys_midiinittime);
|
||||
midi_outhead = newhead;
|
||||
sys_pollmidioutqueue();
|
||||
}
|
||||
|
||||
#define MIDI_NOTEON 144
|
||||
#define MIDI_POLYAFTERTOUCH 160
|
||||
#define MIDI_CONTROLCHANGE 176
|
||||
#define MIDI_PROGRAMCHANGE 192
|
||||
#define MIDI_AFTERTOUCH 208
|
||||
#define MIDI_PITCHBEND 224
|
||||
|
||||
void outmidi_noteon(int portno, int channel, int pitch, int velo)
|
||||
{
|
||||
if (pitch < 0) pitch = 0;
|
||||
else if (pitch > 127) pitch = 127;
|
||||
if (velo < 0) velo = 0;
|
||||
else if (velo > 127) velo = 127;
|
||||
sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
|
||||
}
|
||||
|
||||
void outmidi_controlchange(int portno, int channel, int ctl, int value)
|
||||
{
|
||||
if (ctl < 0) ctl = 0;
|
||||
else if (ctl > 127) ctl = 127;
|
||||
if (value < 0) value = 0;
|
||||
else if (value > 127) value = 127;
|
||||
sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
|
||||
ctl, value);
|
||||
}
|
||||
|
||||
void outmidi_programchange(int portno, int channel, int value)
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
else if (value > 127) value = 127;
|
||||
sys_queuemidimess(portno, 0,
|
||||
MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
|
||||
}
|
||||
|
||||
void outmidi_pitchbend(int portno, int channel, int value)
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
else if (value > 16383) value = 16383;
|
||||
sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
|
||||
(value & 127), ((value>>7) & 127));
|
||||
}
|
||||
|
||||
void outmidi_aftertouch(int portno, int channel, int value)
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
else if (value > 127) value = 127;
|
||||
sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
|
||||
}
|
||||
|
||||
void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
|
||||
{
|
||||
if (pitch < 0) pitch = 0;
|
||||
else if (pitch > 127) pitch = 127;
|
||||
if (value < 0) value = 0;
|
||||
else if (value > 127) value = 127;
|
||||
sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
|
||||
pitch, value);
|
||||
}
|
||||
|
||||
void outmidi_mclk(int portno)
|
||||
{
|
||||
sys_queuemidimess(portno, 1, 0xf8, 0,0);
|
||||
}
|
||||
|
||||
/* ------------------------- MIDI input queue handling ------------------ */
|
||||
typedef struct midiparser
|
||||
{
|
||||
int mp_status;
|
||||
int mp_gotbyte1;
|
||||
int mp_byte1;
|
||||
} t_midiparser;
|
||||
|
||||
#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
|
||||
#define MIDINOTEON 0x90 /* 2 */
|
||||
#define MIDIPOLYTOUCH 0xa0 /* 2 */
|
||||
#define MIDICONTROLCHANGE 0xb0 /* 2 */
|
||||
#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
|
||||
#define MIDICHANNELTOUCH 0xd0 /* 1 */
|
||||
#define MIDIPITCHBEND 0xe0 /* 2 */
|
||||
#define MIDISTARTSYSEX 0xf0 /* (until F7) */
|
||||
#define MIDITIMECODE 0xf1 /* 1 */
|
||||
#define MIDISONGPOS 0xf2 /* 2 */
|
||||
#define MIDISONGSELECT 0xf3 /* 1 */
|
||||
#define MIDIRESERVED1 0xf4 /* ? */
|
||||
#define MIDIRESERVED2 0xf5 /* ? */
|
||||
#define MIDITUNEREQUEST 0xf6 /* 0 */
|
||||
#define MIDIENDSYSEX 0xf7 /* 0 */
|
||||
#define MIDICLOCK 0xf8 /* 0 */
|
||||
#define MIDITICK 0xf9 /* 0 */
|
||||
#define MIDISTART 0xfa /* 0 */
|
||||
#define MIDICONT 0xfb /* 0 */
|
||||
#define MIDISTOP 0xfc /* 0 */
|
||||
#define MIDIACTIVESENSE 0xfe /* 0 */
|
||||
#define MIDIRESET 0xff /* 0 */
|
||||
|
||||
/* functions in x_midi.c */
|
||||
void inmidi_realtimein(int portno, int cmd);
|
||||
void inmidi_byte(int portno, int byte);
|
||||
void inmidi_sysex(int portno, int byte);
|
||||
void inmidi_noteon(int portno, int channel, int pitch, int velo);
|
||||
void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
|
||||
void inmidi_programchange(int portno, int channel, int value);
|
||||
void inmidi_pitchbend(int portno, int channel, int value);
|
||||
void inmidi_aftertouch(int portno, int channel, int value);
|
||||
void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
|
||||
|
||||
static void sys_dispatchnextmidiin( void)
|
||||
{
|
||||
static t_midiparser parser[MAXMIDIINDEV], *parserp;
|
||||
int portno = midi_inqueue[midi_intail].q_portno,
|
||||
byte = midi_inqueue[midi_intail].q_byte1;
|
||||
if (!midi_inqueue[midi_intail].q_onebyte)
|
||||
bug("sys_dispatchnextmidiin");
|
||||
if (portno < 0 || portno >= MAXMIDIINDEV)
|
||||
bug("sys_dispatchnextmidiin 2");
|
||||
parserp = parser + portno;
|
||||
outlet_setstacklim();
|
||||
|
||||
if (byte >= 0xf8)
|
||||
inmidi_realtimein(portno, byte);
|
||||
else
|
||||
{
|
||||
inmidi_byte(portno, byte);
|
||||
if (byte & 0x80)
|
||||
{
|
||||
if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 ||
|
||||
byte == MIDIRESERVED2)
|
||||
parserp->mp_status = 0;
|
||||
else if (byte == MIDISTARTSYSEX)
|
||||
{
|
||||
inmidi_sysex(portno, byte);
|
||||
parserp->mp_status = byte;
|
||||
}
|
||||
else if (byte == MIDIENDSYSEX)
|
||||
{
|
||||
inmidi_sysex(portno, byte);
|
||||
parserp->mp_status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
parserp->mp_status = byte;
|
||||
}
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
|
||||
(parserp->mp_status & 0xf0));
|
||||
int chan = (parserp->mp_status & 0xf);
|
||||
int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
|
||||
switch (cmd)
|
||||
{
|
||||
case MIDINOTEOFF:
|
||||
if (gotbyte1)
|
||||
inmidi_noteon(portno, chan, byte1, 0),
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
|
||||
break;
|
||||
case MIDINOTEON:
|
||||
if (gotbyte1)
|
||||
inmidi_noteon(portno, chan, byte1, byte),
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
|
||||
break;
|
||||
case MIDIPOLYTOUCH:
|
||||
if (gotbyte1)
|
||||
inmidi_polyaftertouch(portno, chan, byte1, byte),
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
|
||||
break;
|
||||
case MIDICONTROLCHANGE:
|
||||
if (gotbyte1)
|
||||
inmidi_controlchange(portno, chan, byte1, byte),
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
|
||||
break;
|
||||
case MIDIPROGRAMCHANGE:
|
||||
inmidi_programchange(portno, chan, byte);
|
||||
break;
|
||||
case MIDICHANNELTOUCH:
|
||||
inmidi_aftertouch(portno, chan, byte);
|
||||
break;
|
||||
case MIDIPITCHBEND:
|
||||
if (gotbyte1)
|
||||
inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
|
||||
parserp->mp_gotbyte1 = 0;
|
||||
else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
|
||||
break;
|
||||
case MIDISTARTSYSEX:
|
||||
inmidi_sysex(portno, byte);
|
||||
break;
|
||||
|
||||
/* other kinds of messages are just dropped here. We'll
|
||||
need another status byte before we start letting MIDI in
|
||||
again (no running status across "system" messages). */
|
||||
case MIDITIMECODE: /* 1 data byte*/
|
||||
break;
|
||||
case MIDISONGPOS: /* 2 */
|
||||
break;
|
||||
case MIDISONGSELECT: /* 1 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
|
||||
}
|
||||
|
||||
void sys_pollmidiinqueue( void)
|
||||
{
|
||||
#ifdef TEST_DEJITTER
|
||||
static int db = 0;
|
||||
#endif
|
||||
double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
|
||||
#ifdef TEST_DEJITTER
|
||||
if (midi_inhead == midi_intail)
|
||||
db = 0;
|
||||
#endif
|
||||
while (midi_inhead != midi_intail)
|
||||
{
|
||||
#ifdef TEST_DEJITTER
|
||||
if (!db)
|
||||
{
|
||||
post("in del %f, logicaltime %f, RT %f adcminusRT %f",
|
||||
(midi_inqueue[midi_intail].q_time - logicaltime),
|
||||
logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
|
||||
db = 1;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
|
||||
post("late %f",
|
||||
1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
|
||||
#endif
|
||||
if (midi_inqueue[midi_intail].q_time <= logicaltime)
|
||||
{
|
||||
#if 0
|
||||
post("diff %f",
|
||||
1000* (logicaltime - midi_inqueue[midi_intail].q_time));
|
||||
#endif
|
||||
sys_dispatchnextmidiin();
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
/* this should be called from the system dependent MIDI code when a byte
|
||||
comes in, as a result of our calling sys_poll_midi. We stick it on a
|
||||
timetag queue and dispatch it at the appropriate logical time. */
|
||||
|
||||
|
||||
void sys_midibytein(int portno, int byte)
|
||||
{
|
||||
static int warned = 0;
|
||||
t_midiqelem *midiqelem;
|
||||
int newhead = midi_inhead +1;
|
||||
if (newhead == MIDIQSIZE)
|
||||
newhead = 0;
|
||||
/* if FIFO is full flush an element to make room */
|
||||
if (newhead == midi_intail)
|
||||
{
|
||||
if (!warned)
|
||||
{
|
||||
post("warning: MIDI timing FIFO overflowed");
|
||||
warned = 1;
|
||||
}
|
||||
sys_dispatchnextmidiin();
|
||||
}
|
||||
midi_inqueue[midi_inhead].q_portno = portno;
|
||||
midi_inqueue[midi_inhead].q_onebyte = 1;
|
||||
midi_inqueue[midi_inhead].q_byte1 = byte;
|
||||
midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
|
||||
midi_inhead = newhead;
|
||||
sys_pollmidiinqueue();
|
||||
}
|
||||
|
||||
void sys_pollmidiqueue( void)
|
||||
{
|
||||
#if 0
|
||||
static double lasttime;
|
||||
double newtime = sys_getrealtime();
|
||||
if (newtime - lasttime > 0.007)
|
||||
post("delay %d", (int)(1000 * (newtime - lasttime)));
|
||||
lasttime = newtime;
|
||||
#endif
|
||||
sys_poll_midi(); /* OS dependent poll for MIDI input */
|
||||
sys_pollmidioutqueue();
|
||||
sys_pollmidiinqueue();
|
||||
}
|
||||
|
||||
/******************** dialog window and device listing ********************/
|
||||
|
||||
#ifdef USEAPI_OSS
|
||||
void midi_oss_init( void);
|
||||
#endif
|
||||
|
||||
/* last requested parameters */
|
||||
static int midi_nmidiindev;
|
||||
static int midi_midiindev[MAXMIDIINDEV];
|
||||
static int midi_nmidioutdev;
|
||||
static int midi_midioutdev[MAXMIDIOUTDEV];
|
||||
|
||||
static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev,
|
||||
int *pnmidioutdev, int *pmidioutdev)
|
||||
{
|
||||
int i;
|
||||
*pnmidiindev = midi_nmidiindev;
|
||||
for (i = 0; i < MAXMIDIINDEV; i++)
|
||||
pmidiindev[i] = midi_midiindev[i];
|
||||
*pnmidioutdev = midi_nmidioutdev;
|
||||
for (i = 0; i < MAXMIDIOUTDEV; i++)
|
||||
pmidioutdev[i] = midi_midioutdev[i];
|
||||
}
|
||||
|
||||
static void sys_save_midi_params(
|
||||
int nmidiindev, int *midiindev,
|
||||
int nmidioutdev, int *midioutdev)
|
||||
{
|
||||
int i;
|
||||
midi_nmidiindev = nmidiindev;
|
||||
for (i = 0; i < MAXMIDIINDEV; i++)
|
||||
midi_midiindev[i] = midiindev[i];
|
||||
midi_nmidioutdev = nmidioutdev;
|
||||
for (i = 0; i < MAXMIDIOUTDEV; i++)
|
||||
midi_midioutdev[i] = midioutdev[i];
|
||||
}
|
||||
|
||||
void sys_open_midi(int nmidiindev, int *midiindev,
|
||||
int nmidioutdev, int *midioutdev)
|
||||
{
|
||||
#ifdef USEAPI_OSS
|
||||
midi_oss_init();
|
||||
#endif
|
||||
sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
|
||||
sys_save_midi_params(nmidiindev, midiindev,
|
||||
nmidioutdev, midioutdev);
|
||||
}
|
||||
|
||||
/* open midi using whatever parameters were last used */
|
||||
void sys_reopen_midi( void)
|
||||
{
|
||||
int nmidiindev, midiindev[MAXMIDIINDEV];
|
||||
int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
|
||||
sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
|
||||
sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
|
||||
}
|
||||
|
||||
#define MAXNDEV 20
|
||||
#define DEVDESCSIZE 80
|
||||
|
||||
#ifdef MSW
|
||||
#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
|
||||
#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
|
||||
#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
|
||||
#endif
|
||||
|
||||
void sys_listmididevs(void )
|
||||
{
|
||||
char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
|
||||
int nindevs = 0, noutdevs = 0, i;
|
||||
|
||||
midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
|
||||
MAXNDEV, DEVDESCSIZE);
|
||||
|
||||
if (!nindevs)
|
||||
post("no midi input devices found");
|
||||
else
|
||||
{
|
||||
post("input devices:");
|
||||
for (i = 0; i < nindevs; i++)
|
||||
post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
|
||||
}
|
||||
if (!noutdevs)
|
||||
post("no midi output devices found");
|
||||
else
|
||||
{
|
||||
post("output devices:");
|
||||
for (i = 0; i < noutdevs; i++)
|
||||
post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
extern t_class *glob_pdobject;
|
||||
|
||||
/* start an midi settings dialog window */
|
||||
void glob_midi_properties(t_pd *dummy, t_floatarg flongform)
|
||||
{
|
||||
char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
|
||||
/* these are the devices you're using: */
|
||||
int nindev, midiindev[MAXMIDIINDEV];
|
||||
int noutdev, midioutdev[MAXMIDIOUTDEV];
|
||||
int midiindev1, midiindev2, midiindev3, midiindev4,
|
||||
midioutdev1, midioutdev2, midioutdev3, midioutdev4;
|
||||
|
||||
/* these are all the devices on your system: */
|
||||
char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
|
||||
int nindevs = 0, noutdevs = 0, i;
|
||||
|
||||
char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
|
||||
outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
|
||||
|
||||
midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
|
||||
MAXNDEV, DEVDESCSIZE);
|
||||
|
||||
strcpy(indevliststring, "{ {none} ");
|
||||
for (i = 0; i < nindevs; i++)
|
||||
{
|
||||
strcat(indevliststring, "\"");
|
||||
strcat(indevliststring, indevlist + i * DEVDESCSIZE);
|
||||
strcat(indevliststring, "\" ");
|
||||
}
|
||||
strcat(indevliststring, "}");
|
||||
|
||||
strcpy(outdevliststring, "{ {none} ");
|
||||
for (i = 0; i < noutdevs; i++)
|
||||
{
|
||||
strcat(outdevliststring, "\"");
|
||||
strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
|
||||
strcat(outdevliststring, "\" ");
|
||||
}
|
||||
strcat(outdevliststring, "}");
|
||||
|
||||
sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
|
||||
|
||||
if (nindev > 1 || noutdev > 1)
|
||||
flongform = 1;
|
||||
|
||||
midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0);
|
||||
midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0);
|
||||
midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0);
|
||||
midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0);
|
||||
midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0);
|
||||
midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0);
|
||||
midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0);
|
||||
midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0);
|
||||
|
||||
sprintf(buf,
|
||||
"pdtk_midi_dialog %%s \
|
||||
%s %d %d %d %d %s %d %d %d %d \
|
||||
%d\n",
|
||||
indevliststring,
|
||||
midiindev1, midiindev2, midiindev3, midiindev4,
|
||||
outdevliststring,
|
||||
midioutdev1, midioutdev2, midioutdev3, midioutdev4,
|
||||
(flongform != 0));
|
||||
gfxstub_deleteforkey(0);
|
||||
gfxstub_new(&glob_pdobject, glob_midi_properties, buf);
|
||||
}
|
||||
|
||||
/* new values from dialog window */
|
||||
void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
int nmidiindev, midiindev[MAXMIDIINDEV];
|
||||
int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
|
||||
int i, nindev, noutdev;
|
||||
int newmidiindev[4], newmidioutdev[4];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
newmidiindev[i] = atom_getintarg(i, argc, argv);
|
||||
newmidioutdev[i] = atom_getintarg(i+4, argc, argv);
|
||||
}
|
||||
|
||||
for (i = 0, nindev = 0; i < 4; i++)
|
||||
{
|
||||
if (newmidiindev[i] > 0)
|
||||
{
|
||||
newmidiindev[nindev] = newmidiindev[i]-1;
|
||||
nindev++;
|
||||
}
|
||||
}
|
||||
for (i = 0, noutdev = 0; i < 4; i++)
|
||||
{
|
||||
if (newmidioutdev[i] > 0)
|
||||
{
|
||||
newmidioutdev[noutdev] = newmidioutdev[i]-1;
|
||||
noutdev++;
|
||||
}
|
||||
}
|
||||
|
||||
sys_close_midi();
|
||||
sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev);
|
||||
}
|
||||
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
|
||||
* Winfried Ritsch, Karl MacMillan, and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* MIDI I/O for Linux using OSS */
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
|
||||
static int oss_nmidiin;
|
||||
static int oss_midiinfd[MAXMIDIINDEV];
|
||||
static int oss_nmidiout;
|
||||
static int oss_midioutfd[MAXMIDIOUTDEV];
|
||||
|
||||
static void oss_midiout(int fd, int n)
|
||||
{
|
||||
char b = n;
|
||||
if ((write(fd, (char *) &b, 1)) != 1)
|
||||
perror("midi write");
|
||||
}
|
||||
|
||||
#define O_MIDIFLAG O_NDELAY
|
||||
|
||||
void sys_do_open_midi(int nmidiin, int *midiinvec,
|
||||
int nmidiout, int *midioutvec)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nmidiout; i++)
|
||||
oss_midioutfd[i] = -1;
|
||||
for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
|
||||
{
|
||||
int fd = -1, j, outdevindex = -1;
|
||||
char namebuf[80];
|
||||
int devno = midiinvec[i];
|
||||
|
||||
for (j = 0; j < nmidiout; j++)
|
||||
if (midioutvec[j] == midiinvec[i])
|
||||
outdevindex = j;
|
||||
|
||||
/* try to open the device for read/write. */
|
||||
if (devno == 0 && fd < 0 && outdevindex >= 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,
|
||||
"device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
|
||||
if (outdevindex >= 0 && fd >= 0)
|
||||
oss_midioutfd[outdevindex] = fd;
|
||||
}
|
||||
if (fd < 0 && outdevindex >= 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%2.2d", devno);
|
||||
fd = open(namebuf, O_RDWR | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,
|
||||
"device %d: tried %s READ/WRITE; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
if (outdevindex >= 0 && fd >= 0)
|
||||
oss_midioutfd[outdevindex] = fd;
|
||||
}
|
||||
if (fd < 0 && outdevindex >= 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%d", devno);
|
||||
fd = open(namebuf, O_RDWR | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
if (outdevindex >= 0 && fd >= 0)
|
||||
oss_midioutfd[outdevindex] = fd;
|
||||
}
|
||||
if (devno == 1 && fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,
|
||||
"device 1: tried /dev/midi READONLY; returned %d\n", fd);
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%2.2d", devno);
|
||||
fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%d", devno);
|
||||
fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
}
|
||||
if (fd >= 0)
|
||||
oss_midiinfd[oss_nmidiin++] = fd;
|
||||
else post("couldn't open MIDI input device %d", devno);
|
||||
}
|
||||
for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
|
||||
{
|
||||
int fd = oss_midioutfd[i];
|
||||
char namebuf[80];
|
||||
int devno = midioutvec[i];
|
||||
if (devno == 1 && fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr,
|
||||
"device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%2.2d", devno);
|
||||
fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
sys_setalarm(1000000);
|
||||
sprintf(namebuf, "/dev/midi%d", devno);
|
||||
fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
|
||||
if (sys_verbose)
|
||||
fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
|
||||
devno, namebuf, fd);
|
||||
}
|
||||
if (fd >= 0)
|
||||
oss_midioutfd[oss_nmidiout++] = fd;
|
||||
else post("couldn't open MIDI output device %d", devno);
|
||||
}
|
||||
|
||||
if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
|
||||
post("opened %d MIDI input device(s) and %d MIDI output device(s).",
|
||||
oss_nmidiin, oss_nmidiout);
|
||||
|
||||
sys_setalarm(0);
|
||||
}
|
||||
|
||||
#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
|
||||
((x)==0xF2)?2:((x)<0xF4)?1:0)
|
||||
|
||||
void sys_putmidimess(int portno, int a, int b, int c)
|
||||
{
|
||||
if (portno >= 0 && portno < oss_nmidiout)
|
||||
{
|
||||
switch (md_msglen(a))
|
||||
{
|
||||
case 2:
|
||||
oss_midiout(oss_midioutfd[portno],a);
|
||||
oss_midiout(oss_midioutfd[portno],b);
|
||||
oss_midiout(oss_midioutfd[portno],c);
|
||||
return;
|
||||
case 1:
|
||||
oss_midiout(oss_midioutfd[portno],a);
|
||||
oss_midiout(oss_midioutfd[portno],b);
|
||||
return;
|
||||
case 0:
|
||||
oss_midiout(oss_midioutfd[portno],a);
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void sys_putmidibyte(int portno, int byte)
|
||||
{
|
||||
if (portno >= 0 && portno < oss_nmidiout)
|
||||
oss_midiout(oss_midioutfd[portno], byte);
|
||||
}
|
||||
|
||||
#if 0 /* this is the "select" version which doesn't work with OSS
|
||||
driver for emu10k1 (it doesn't implement select.) */
|
||||
void sys_poll_midi(void)
|
||||
{
|
||||
int i, throttle = 100;
|
||||
struct timeval timout;
|
||||
int did = 1, maxfd = 0;
|
||||
while (did)
|
||||
{
|
||||
fd_set readset, writeset, exceptset;
|
||||
did = 0;
|
||||
if (throttle-- < 0)
|
||||
break;
|
||||
timout.tv_sec = 0;
|
||||
timout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&writeset);
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&exceptset);
|
||||
for (i = 0; i < oss_nmidiin; i++)
|
||||
{
|
||||
if (oss_midiinfd[i] > maxfd)
|
||||
maxfd = oss_midiinfd[i];
|
||||
FD_SET(oss_midiinfd[i], &readset);
|
||||
}
|
||||
select(maxfd+1, &readset, &writeset, &exceptset, &timout);
|
||||
for (i = 0; i < oss_nmidiin; i++)
|
||||
if (FD_ISSET(oss_midiinfd[i], &readset))
|
||||
{
|
||||
char c;
|
||||
int ret = read(oss_midiinfd[i], &c, 1);
|
||||
if (ret <= 0)
|
||||
fprintf(stderr, "Midi read error\n");
|
||||
else sys_midibytein(i, (c & 0xff));
|
||||
did = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
/* this version uses the asynchronous "read()" ... */
|
||||
void sys_poll_midi(void)
|
||||
{
|
||||
int i, throttle = 100;
|
||||
struct timeval timout;
|
||||
int did = 1, maxfd = 0;
|
||||
while (did)
|
||||
{
|
||||
fd_set readset, writeset, exceptset;
|
||||
did = 0;
|
||||
if (throttle-- < 0)
|
||||
break;
|
||||
for (i = 0; i < oss_nmidiin; i++)
|
||||
{
|
||||
char c;
|
||||
int ret = read(oss_midiinfd[i], &c, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
perror("MIDI");
|
||||
}
|
||||
else if (ret != 0)
|
||||
{
|
||||
sys_midibytein(i, (c & 0xff));
|
||||
did = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void sys_close_midi()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < oss_nmidiin; i++)
|
||||
close(oss_midiinfd[i]);
|
||||
for (i = 0; i < oss_nmidiout; i++)
|
||||
close(oss_midioutfd[i]);
|
||||
oss_nmidiin = oss_nmidiout = 0;
|
||||
}
|
||||
|
||||
#define NSEARCH 10
|
||||
static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted;
|
||||
|
||||
void midi_oss_init(void)
|
||||
{
|
||||
int i;
|
||||
if (oss_initted)
|
||||
return;
|
||||
oss_initted = 1;
|
||||
for (i = 0; i < NSEARCH; i++)
|
||||
{
|
||||
int fd;
|
||||
char namebuf[80];
|
||||
|
||||
oss_nmidiindevs = i;
|
||||
/* try to open the device for reading */
|
||||
if (i == 0)
|
||||
{
|
||||
fd = open("/dev/midi", O_RDONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sprintf(namebuf, "/dev/midi%2.2d", i);
|
||||
fd = open(namebuf, O_RDONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
sprintf(namebuf, "/dev/midi%d", i);
|
||||
fd = open(namebuf, O_RDONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < NSEARCH; i++)
|
||||
{
|
||||
int fd;
|
||||
char namebuf[80];
|
||||
|
||||
oss_nmidioutdevs = i;
|
||||
/* try to open the device for writing */
|
||||
if (i == 0)
|
||||
{
|
||||
fd = open("/dev/midi", O_WRONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sprintf(namebuf, "/dev/midi%2.2d", i);
|
||||
fd = open(namebuf, O_WRONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
sprintf(namebuf, "/dev/midi%d", i);
|
||||
fd = open(namebuf, O_WRONLY | O_NDELAY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void midi_getdevs(char *indevlist, int *nindevs,
|
||||
char *outdevlist, int *noutdevs, int maxndev, int devdescsize)
|
||||
{
|
||||
int i, ndev;
|
||||
if ((ndev = oss_nmidiindevs) > maxndev)
|
||||
ndev = maxndev;
|
||||
for (i = 0; i < ndev; i++)
|
||||
sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
|
||||
*nindevs = ndev;
|
||||
|
||||
if ((ndev = oss_nmidioutdevs) > maxndev)
|
||||
ndev = maxndev;
|
||||
for (i = 0; i < ndev; i++)
|
||||
sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
|
||||
*noutdevs = ndev;
|
||||
}
|
||||
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
|
||||
* Winfried Ritsch, Karl MacMillan, and others.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
|
||||
|
||||
this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
|
||||
|
||||
*/
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "s_stuff.h"
|
||||
#include <stdio.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "portaudio.h"
|
||||
#include "portmidi.h"
|
||||
#include "porttime.h"
|
||||
#include "pminternal.h"
|
||||
|
||||
static PmStream *mac_midiindevlist[MAXMIDIINDEV];
|
||||
static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
|
||||
static int mac_nmidiindev;
|
||||
static int mac_nmidioutdev;
|
||||
|
||||
void sys_open_midi(int nmidiin, int *midiinvec,
|
||||
int nmidiout, int *midioutvec)
|
||||
{
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
PmError err;
|
||||
|
||||
Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
|
||||
mac_nmidiindev = 0;
|
||||
|
||||
/* protect the unwary from having MIDI inputs open; they're
|
||||
bad news if you close Pd's terminal window. see sys_nmidiin
|
||||
in s_main.c too. */
|
||||
#ifdef MSW
|
||||
if (nmidiin)
|
||||
{
|
||||
post(
|
||||
"midi input enabled; warning, don't close the DOS window directly!");
|
||||
}
|
||||
else post("not using MIDI input (use 'pd -midiindev 1' to override)");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < nmidiin; i++)
|
||||
{
|
||||
if (midiinvec[i] == DEFMIDIDEV)
|
||||
midiinvec[i] = Pm_GetDefaultInputDeviceID();
|
||||
err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i],
|
||||
NULL, 100, NULL, NULL, NULL);
|
||||
if (err)
|
||||
post("could not open midi input device number %d: %s",
|
||||
midiinvec[i], Pm_GetErrorText(err));
|
||||
else
|
||||
{
|
||||
if (sys_verbose)
|
||||
post("Midi Input opened.\n");
|
||||
mac_nmidiindev++;
|
||||
}
|
||||
}
|
||||
|
||||
mac_nmidioutdev = 0;
|
||||
for (i = 0; i < nmidiout; i++)
|
||||
{
|
||||
if (midioutvec[i] == DEFMIDIDEV)
|
||||
midioutvec[i] = Pm_GetDefaultOutputDeviceID();
|
||||
err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i],
|
||||
NULL, 0, NULL, NULL, 0);
|
||||
if (err)
|
||||
post("could not open midi output device number %d: %s",
|
||||
midioutvec[i], Pm_GetErrorText(err));
|
||||
else
|
||||
{
|
||||
if (sys_verbose)
|
||||
post("Midi Output opened.\n");
|
||||
mac_nmidioutdev++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sys_close_midi( void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < mac_nmidiindev; i++)
|
||||
Pm_Close(mac_midiindevlist[mac_nmidiindev]);
|
||||
mac_nmidiindev = 0;
|
||||
for (i = 0; i < mac_nmidioutdev; i++)
|
||||
Pm_Close(mac_midioutdevlist[mac_nmidioutdev]);
|
||||
mac_nmidioutdev = 0;
|
||||
}
|
||||
|
||||
void sys_putmidimess(int portno, int a, int b, int c)
|
||||
{
|
||||
PmEvent buffer;
|
||||
fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev);
|
||||
if (portno >= 0 && portno < mac_nmidioutdev)
|
||||
{
|
||||
buffer.message = Pm_Message(a, b, c);
|
||||
buffer.timestamp = 0;
|
||||
fprintf(stderr, "put msg\n");
|
||||
Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_putmidibyte(int portno, int byte)
|
||||
{
|
||||
post("sorry, no byte-by-byte MIDI output implemented in MAC OSX");
|
||||
}
|
||||
|
||||
void sys_poll_midi(void)
|
||||
{
|
||||
int i, nmess;
|
||||
PmEvent buffer;
|
||||
for (i = 0; i < mac_nmidiindev; i++)
|
||||
{
|
||||
int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
|
||||
if (nmess > 0)
|
||||
{
|
||||
int status = Pm_MessageStatus(buffer.message);
|
||||
int data1 = Pm_MessageData1(buffer.message);
|
||||
int data2 = Pm_MessageData2(buffer.message);
|
||||
int msgtype = (status >> 4) - 8;
|
||||
switch (msgtype)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
sys_midibytein(i, status);
|
||||
sys_midibytein(i, data1);
|
||||
sys_midibytein(i, data2);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
sys_midibytein(i, status);
|
||||
sys_midibytein(i, data1);
|
||||
break;
|
||||
case 7:
|
||||
sys_midibytein(i, status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */
|
||||
{
|
||||
int i,j;
|
||||
for (i = 0; i < Pm_CountDevices(); i++)
|
||||
{
|
||||
const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
|
||||
printf("%d: %s, %s", i, info->interf, info->name);
|
||||
if (info->input) printf(" (input)");
|
||||
if (info->output) printf(" (output)");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
#include "s_stuff.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_BSTRING_H
|
||||
#include <bstring.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <dmedia/audio.h>
|
||||
#include <sys/fpu.h>
|
||||
#include <dmedia/midi.h>
|
||||
int mdInit(void); /* prototype was messed up in midi.h */
|
||||
/* #include "sys/select.h" */
|
||||
|
||||
|
||||
/*
|
||||
set the special "flush zero" but (FS, bit 24) in the
|
||||
Control Status Register of the FPU of R4k and beyond
|
||||
so that the result of any underflowing operation will
|
||||
be clamped to zero, and no exception of any kind will
|
||||
be generated on the CPU.
|
||||
|
||||
thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi).
|
||||
*/
|
||||
|
||||
static void sgi_flush_all_underflows_to_zero(void)
|
||||
{
|
||||
union fpc_csr f;
|
||||
f.fc_word = get_fpc_csr();
|
||||
f.fc_struct.flush = 1;
|
||||
set_fpc_csr(f.fc_word);
|
||||
}
|
||||
|
||||
#define NPORT 2
|
||||
|
||||
static MDport sgi_inport[NPORT];
|
||||
static MDport sgi_outport[NPORT];
|
||||
|
||||
void sgi_open_midi(int midiin, int midiout)
|
||||
{
|
||||
int i;
|
||||
int sgi_nports = mdInit();
|
||||
if (sgi_nports < 0) sgi_nports = 0;
|
||||
else if (sgi_nports > NPORT) sgi_nports = NPORT;
|
||||
if (sys_verbose)
|
||||
{
|
||||
if (!sgi_nports)
|
||||
{
|
||||
post("no serial ports are configured for MIDI;");
|
||||
post("if you want to use MIDI, try exiting Pd, typing");
|
||||
post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
|
||||
}
|
||||
else if (sgi_nports == 1)
|
||||
post("Found one MIDI port on %s", mdGetName(0));
|
||||
else if (sgi_nports == 2)
|
||||
post("Found MIDI ports on %s and %s",
|
||||
mdGetName(0), mdGetName(1));
|
||||
}
|
||||
if (midiin)
|
||||
{
|
||||
for (i = 0; i < sgi_nports; i++)
|
||||
{
|
||||
if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i))))
|
||||
error("MIDI input port %d: open failed", i+1);;
|
||||
}
|
||||
}
|
||||
if (midiout)
|
||||
{
|
||||
for (i = 0; i < sgi_nports; i++)
|
||||
{
|
||||
if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i))))
|
||||
error("MIDI output port %d: open failed", i+1);;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sys_putmidimess(int portno, int a, int b, int c)
|
||||
{
|
||||
MDevent mdv;
|
||||
if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
|
||||
mdv.msg[0] = a;
|
||||
mdv.msg[1] = b;
|
||||
mdv.msg[2] = c;
|
||||
mdv.msg[3] = 0;
|
||||
mdv.sysexmsg = 0;
|
||||
mdv.stamp = 0;
|
||||
mdv.msglen = 0;
|
||||
if (mdSend(sgi_outport[portno], &mdv, 1) < 0)
|
||||
error("MIDI output error\n");
|
||||
post("msg out %d %d %d", a, b, c);
|
||||
}
|
||||
|
||||
void sys_putmidibyte(int portno, int foo)
|
||||
{
|
||||
error("MIDI raw byte output not available on SGI");
|
||||
}
|
||||
|
||||
void inmidi_noteon(int portno, int channel, int pitch, int velo);
|
||||
void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
|
||||
void inmidi_programchange(int portno, int channel, int value);
|
||||
void inmidi_pitchbend(int portno, int channel, int value);
|
||||
void inmidi_aftertouch(int portno, int channel, int value);
|
||||
void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
|
||||
|
||||
void sys_poll_midi(void)
|
||||
{
|
||||
int i;
|
||||
MDport *mp;
|
||||
for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++)
|
||||
{
|
||||
int ret, status, b1, b2, nfds;
|
||||
MDevent mdv;
|
||||
fd_set inports;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (!*mp) continue;
|
||||
FD_ZERO(&inports);
|
||||
FD_SET(mdGetFd(*mp), &inports);
|
||||
|
||||
if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0)
|
||||
perror("midi select");
|
||||
if (FD_ISSET(mdGetFd(*mp),&inports))
|
||||
{
|
||||
if (mdReceive(*mp, &mdv, 1) < 0)
|
||||
error("failure receiving message\n");
|
||||
else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
|
||||
|
||||
else
|
||||
{
|
||||
int status = mdv.msg[0];
|
||||
int channel = (status & 0xf) + 1;
|
||||
int b1 = mdv.msg[1];
|
||||
int b2 = mdv.msg[2];
|
||||
switch(status & 0xf0)
|
||||
{
|
||||
case MD_NOTEOFF:
|
||||
inmidi_noteon(i, channel, b1, 0);
|
||||
break;
|
||||
case MD_NOTEON:
|
||||
inmidi_noteon(i, channel, b1, b2);
|
||||
break;
|
||||
case MD_POLYKEYPRESSURE:
|
||||
inmidi_polyaftertouch(i, channel, b1, b2);
|
||||
break;
|
||||
case MD_CONTROLCHANGE:
|
||||
inmidi_controlchange(i, channel, b1, b2);
|
||||
break;
|
||||
case MD_PITCHBENDCHANGE:
|
||||
inmidi_pitchbend(i, channel, ((b2 << 7) + b1));
|
||||
break;
|
||||
case MD_PROGRAMCHANGE:
|
||||
inmidi_programchange(i, channel, b1);
|
||||
break;
|
||||
case MD_CHANNELPRESSURE:
|
||||
inmidi_aftertouch(i, channel, b1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sys_open_midi(int nmidiin, int *midiinvec,
|
||||
int nmidiout, int *midioutvec)
|
||||
{
|
||||
sgi_open_midi(nmidiin!=0, nmidiout!=0);
|
||||
}
|
||||
|
||||
|
||||
void sys_close_midi( void)
|
||||
{
|
||||
/* ??? */
|
||||
}
|
||||
|
||||
void sys_set_priority(int foo)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"warning: priority boosting in IRIX not implemented yet\n");
|
||||
}
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* Copyright (c) 1997-2000 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* This file is compiled into the separate program, "pd-watchdog," which
|
||||
tries to prevent Pd from locking up the processor if it's at realtime
|
||||
priority. Linux only. Invoked from s_inter.c. */
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int happy = 1;
|
||||
while (1)
|
||||
{
|
||||
struct timeval timout;
|
||||
fd_set readset;
|
||||
if (happy)
|
||||
{
|
||||
timout.tv_sec = 5;
|
||||
timout.tv_usec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
timout.tv_sec = 2;
|
||||
timout.tv_usec = 0;
|
||||
}
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(0, &readset);
|
||||
select(1, &readset, 0, 0, &timout);
|
||||
if (FD_ISSET(0, &readset))
|
||||
{
|
||||
char buf[100];
|
||||
happy = 1;
|
||||
if (read(0, &buf, 100) <= 0)
|
||||
return (0);
|
||||
else continue;
|
||||
}
|
||||
happy = 0;
|
||||
kill(getppid(), SIGHUP);
|
||||
fprintf(stderr, "watchdog: signaling pd...\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* This file should be compared with the corresponding thing in the TK
|
||||
* distribution whenever updating to newer versions of TCL/TK. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MACOSX /* linux and IRIX only; in MACOSX we don't link this in */
|
||||
#include "tk.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* The following variable is a special hack that is needed in order for
|
||||
* Sun shared libraries to be used for Tcl.
|
||||
*/
|
||||
|
||||
extern int matherr(void);
|
||||
int *tclDummyMathPtr = (int *) matherr;
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* main --
|
||||
*
|
||||
* This is the main program for the application.
|
||||
*
|
||||
* Results:
|
||||
* None: Tk_Main never returns here, so this procedure never
|
||||
* returns either.
|
||||
*
|
||||
* Side effects:
|
||||
* Whatever the application does.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void pdgui_startup(Tcl_Interp *interp);
|
||||
void pdgui_setname(char *name);
|
||||
void pdgui_setsock(int port);
|
||||
void pdgui_sethost(char *name);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
pdgui_setname(argv[0]);
|
||||
if (argc >= 2)
|
||||
{
|
||||
pdgui_setsock(atoi(argv[1]));
|
||||
argc--; argv++;
|
||||
argv[0] = "Pd";
|
||||
}
|
||||
if (argc >= 2)
|
||||
{
|
||||
pdgui_sethost(argv[1]);
|
||||
argc--; argv++;
|
||||
argv[0] = "Pd";
|
||||
}
|
||||
Tk_Main(argc, argv, Tcl_AppInit);
|
||||
return 0; /* Needed only to prevent compiler warning. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_AppInit --
|
||||
*
|
||||
* This procedure performs application-specific initialization.
|
||||
* Most applications, especially those that incorporate additional
|
||||
* packages, will have their own version of this procedure.
|
||||
* Results:
|
||||
* Returns a standard Tcl completion code, and leaves an error
|
||||
* message in interp->result if an error occurs.
|
||||
*
|
||||
* Side effects:
|
||||
* Depends on the startup script.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_AppInit(interp)
|
||||
Tcl_Interp *interp; /* Interpreter for application. */
|
||||
{
|
||||
|
||||
if (Tcl_Init(interp) == TCL_ERROR) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tk_Init(interp) == TCL_ERROR) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* setup specific to pd-gui: */
|
||||
|
||||
pdgui_startup(interp);
|
||||
|
||||
/*
|
||||
* Specify a user-specific startup file to invoke if the application
|
||||
* is run interactively. Typically the startup file is "~/.apprc"
|
||||
* where "app" is the name of the application. If this line is deleted
|
||||
* then no user-specific startup file will be run under any conditions.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
tcl_RcFileName = "~/.pdrc";
|
||||
#endif
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif /* MACOSX */
|
||||
|
||||
|
|
@ -1,398 +0,0 @@
|
|||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
#ifdef UNIX /* in unix this only works first; in NT it only works last. */
|
||||
#include "tk.h"
|
||||
#endif
|
||||
|
||||
#include "t_tk.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_BSTRING_H
|
||||
#include <bstring.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef MSW
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
#ifdef MSW
|
||||
#pragma warning( disable : 4305 ) /* uncast const double to float */
|
||||
#pragma warning( disable : 4244 ) /* uncast double to float */
|
||||
#pragma warning( disable : 4101 ) /* unused local variables */
|
||||
#endif
|
||||
|
||||
#ifdef MSW
|
||||
#include "tk.h"
|
||||
#endif
|
||||
|
||||
void tcl_mess(char *s);
|
||||
|
||||
/***************** the socket setup code ********************/
|
||||
|
||||
static int portno = 5400;
|
||||
|
||||
/* some installations of linux don't know about "localhost" so give
|
||||
the loopback address; NT, on the other hand, can't understand the
|
||||
hostname "127.0.0.1". */
|
||||
char hostname[100] =
|
||||
#ifdef __linux__
|
||||
"127.0.0.1";
|
||||
#else
|
||||
"localhost";
|
||||
#endif
|
||||
|
||||
void pdgui_setsock(int port)
|
||||
{
|
||||
portno = port;
|
||||
}
|
||||
|
||||
void pdgui_sethost(char *name)
|
||||
{
|
||||
strncpy(hostname, name, 100);
|
||||
hostname[99] = 0;
|
||||
}
|
||||
|
||||
static void pdgui_sockerror(char *s)
|
||||
{
|
||||
#ifdef MSW
|
||||
int err = WSAGetLastError();
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
int err = errno;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
|
||||
tcl_mess("exit\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int sockfd;
|
||||
|
||||
/* The "pd_suck" command, which polls the socket.
|
||||
FIXME: if Pd sends something bigger than SOCKSIZE we're in trouble!
|
||||
This has to be set bigger than any array update message for instance.
|
||||
*/
|
||||
#define SOCKSIZE 20000
|
||||
|
||||
static char pd_tkbuf[SOCKSIZE+1];
|
||||
int pd_spillbytes = 0;
|
||||
|
||||
static void pd_readsocket(ClientData cd, int mask)
|
||||
{
|
||||
int ngot;
|
||||
fd_set readset, writeset, exceptset;
|
||||
struct timeval timout;
|
||||
|
||||
timout.tv_sec = 0;
|
||||
timout.tv_usec = 0;
|
||||
FD_ZERO(&writeset);
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&exceptset);
|
||||
FD_SET(sockfd, &readset);
|
||||
FD_SET(sockfd, &exceptset);
|
||||
|
||||
if (select(sockfd+1, &readset, &writeset, &exceptset, &timout) < 0)
|
||||
perror("select");
|
||||
if (FD_ISSET(sockfd, &exceptset) || FD_ISSET(sockfd, &readset))
|
||||
{
|
||||
int ret;
|
||||
ret = recv(sockfd, pd_tkbuf + pd_spillbytes,
|
||||
SOCKSIZE - pd_spillbytes, 0);
|
||||
if (ret < 0) pdgui_sockerror("socket receive error");
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
|
||||
fprintf(stderr, "pd_gui: pd process exited\n");
|
||||
tcl_mess("exit\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *lastcr = 0, *bp = pd_tkbuf, *ep = bp + (pd_spillbytes + ret);
|
||||
int brace = 0;
|
||||
char lastc = 0;
|
||||
while (bp < ep)
|
||||
{
|
||||
char c = *bp;
|
||||
if (c == '}' && brace) brace--;
|
||||
else if (c == '{') brace++;
|
||||
else if (!brace && c == '\n' && lastc != '\\') lastcr = bp;
|
||||
lastc = c;
|
||||
bp++;
|
||||
}
|
||||
if (lastcr)
|
||||
{
|
||||
int xtra = pd_tkbuf + pd_spillbytes + ret - (lastcr+1);
|
||||
char bashwas = lastcr[1];
|
||||
lastcr[1] = 0;
|
||||
tcl_mess(pd_tkbuf);
|
||||
lastcr[1] = bashwas;
|
||||
if (xtra)
|
||||
{
|
||||
/* fprintf(stderr, "x %d\n", xtra); */
|
||||
memmove(pd_tkbuf, lastcr+1, xtra);
|
||||
}
|
||||
pd_spillbytes = xtra;
|
||||
}
|
||||
else
|
||||
{
|
||||
pd_spillbytes += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef UNIX
|
||||
/* if we aren't UNIX, we add a tcl command to poll the
|
||||
socket for data. */
|
||||
static int pd_pollsocketCmd(ClientData cd, Tcl_Interp *interp,
|
||||
int argc, char **argv)
|
||||
{
|
||||
pd_readsocket(cd, 0);
|
||||
return (TCL_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
void pdgui_setupsocket(void)
|
||||
{
|
||||
struct sockaddr_in server;
|
||||
struct hostent *hp;
|
||||
#ifdef UNIX
|
||||
int retry = 10;
|
||||
#else
|
||||
int retry = 1;
|
||||
#endif
|
||||
#ifdef MSW
|
||||
short version = MAKEWORD(2, 0);
|
||||
WSADATA nobby;
|
||||
|
||||
if (WSAStartup(version, &nobby)) pdgui_sockerror("setup");
|
||||
#endif
|
||||
|
||||
/* create a socket */
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) pdgui_sockerror("socket");
|
||||
|
||||
/* connect socket using hostname provided in command line */
|
||||
server.sin_family = AF_INET;
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
if (hp == 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"localhost not found (inet protocol not installed?)\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
|
||||
|
||||
/* assign client port number */
|
||||
server.sin_port = htons((unsigned short)portno);
|
||||
|
||||
/* try to connect */
|
||||
while (1)
|
||||
{
|
||||
if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
|
||||
goto gotit;
|
||||
retry--;
|
||||
if (retry <= 0)
|
||||
break;
|
||||
/* In UNIX there's a race condition; the child won't be
|
||||
able to connect before the parent (pd) has shed its
|
||||
setuid-ness. In case this is the problem, sleep and
|
||||
retry. */
|
||||
else
|
||||
{
|
||||
#ifdef UNIX
|
||||
fd_set readset, writeset, exceptset;
|
||||
struct timeval timout;
|
||||
|
||||
timout.tv_sec = 0;
|
||||
timout.tv_usec = 100000;
|
||||
FD_ZERO(&writeset);
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&exceptset);
|
||||
fprintf(stderr, "retrying connect...\n");
|
||||
if (select(1, &readset, &writeset, &exceptset, &timout) < 0)
|
||||
perror("select");
|
||||
#endif /* UNIX */
|
||||
}
|
||||
}
|
||||
pdgui_sockerror("connecting stream socket");
|
||||
gotit: ;
|
||||
#ifdef UNIX
|
||||
/* in unix we ask TK to call us back. In NT we have to poll. */
|
||||
Tk_CreateFileHandler(sockfd, TK_READABLE | TK_EXCEPTION,
|
||||
pd_readsocket, 0);
|
||||
#endif /* UNIX */
|
||||
}
|
||||
|
||||
/**************************** commands ************************/
|
||||
static char *pdgui_path;
|
||||
|
||||
/* The "pd" command, which cats its args together and throws the result
|
||||
* at the Pd interpreter.
|
||||
*/
|
||||
#define MAXWRITE 1024
|
||||
|
||||
static int pdCmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2)
|
||||
{
|
||||
int n = strlen(argv[1]);
|
||||
if (send(sockfd, argv[1], n, 0) < n)
|
||||
{
|
||||
perror("stdout");
|
||||
tcl_mess("exit\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
char buf[MAXWRITE];
|
||||
buf[0] = 0;
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strlen(argv[i]) + strlen(buf) + 2 > MAXWRITE)
|
||||
{
|
||||
interp->result = "pd: arg list too long";
|
||||
return (TCL_ERROR);
|
||||
}
|
||||
if (i > 1) strcat(buf, " ");
|
||||
strcat(buf, argv[i]);
|
||||
}
|
||||
if (send(sockfd, buf, strlen(buf), 0) < 0)
|
||||
{
|
||||
perror("stdout");
|
||||
tcl_mess("exit\n");
|
||||
}
|
||||
}
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
/*********** "c" level access to tk functions. ******************/
|
||||
|
||||
static Tcl_Interp *tk_myinterp;
|
||||
|
||||
void tcl_mess(char *s)
|
||||
{
|
||||
int result;
|
||||
result = Tcl_Eval(tk_myinterp, s);
|
||||
if (result != TCL_OK)
|
||||
{
|
||||
if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
|
||||
}
|
||||
}
|
||||
|
||||
/* LATER should do a bounds check -- but how do you get printf to do that? */
|
||||
void tcl_vmess(char *fmt, ...)
|
||||
{
|
||||
int result, i;
|
||||
char buf[MAXWRITE];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsprintf(buf, fmt, ap);
|
||||
result = Tcl_Eval(tk_myinterp, buf);
|
||||
if (result != TCL_OK)
|
||||
{
|
||||
if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef UNIX
|
||||
void pdgui_doevalfile(Tcl_Interp *interp, char *s)
|
||||
{
|
||||
char buf[GUISTRING];
|
||||
sprintf(buf, "set pd_guidir \"%s\"\n", pdgui_path);
|
||||
tcl_mess(buf);
|
||||
strcpy(buf, pdgui_path);
|
||||
strcat(buf, "/bin/");
|
||||
strcat(buf, s);
|
||||
if (Tcl_EvalFile(interp, buf) != TCL_OK)
|
||||
{
|
||||
char buf2[1000];
|
||||
sprintf(buf2, "puts [concat tcl: %s: can't open script]\n",
|
||||
buf);
|
||||
tcl_mess(buf2);
|
||||
}
|
||||
}
|
||||
|
||||
void pdgui_evalfile(char *s)
|
||||
{
|
||||
pdgui_doevalfile(tk_myinterp, s);
|
||||
}
|
||||
#endif
|
||||
|
||||
void pdgui_startup(Tcl_Interp *interp)
|
||||
{
|
||||
|
||||
/* save pointer to the main interpreter */
|
||||
tk_myinterp = interp;
|
||||
|
||||
|
||||
/* add our own TK commands */
|
||||
Tcl_CreateCommand(interp, "pd", (Tcl_CmdProc*)pdCmd, (ClientData)NULL,
|
||||
(Tcl_CmdDeleteProc *)NULL);
|
||||
#ifndef UNIX
|
||||
Tcl_CreateCommand(interp, "pd_pollsocket",(Tcl_CmdProc*) pd_pollsocketCmd,
|
||||
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||
#endif
|
||||
pdgui_setupsocket();
|
||||
|
||||
/* read in the startup file */
|
||||
#if !defined(MSW) && !defined(MACOSX)
|
||||
pdgui_evalfile("pd.tk");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNIX
|
||||
void pdgui_setname(char *s)
|
||||
{
|
||||
char *t;
|
||||
char *str;
|
||||
int n;
|
||||
if (t = strrchr(s, '/')) str = s, n = (t-s) + 1;
|
||||
else str = "./", n = 2;
|
||||
if (n > GUISTRING-100) n = GUISTRING-100;
|
||||
pdgui_path = malloc(n+9);
|
||||
|
||||
strncpy(pdgui_path, str, n);
|
||||
while (strlen(pdgui_path) > 0 && pdgui_path[strlen(pdgui_path)-1] == '/')
|
||||
pdgui_path[strlen(pdgui_path)-1] = 0;
|
||||
if (t = strrchr(pdgui_path, '/'))
|
||||
*t = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int Pdtcl_Init(Tcl_Interp *interp)
|
||||
{
|
||||
const char *myvalue = Tcl_GetVar(interp, "argv", 0);
|
||||
int myportno;
|
||||
if (myvalue && (myportno = atoi(myvalue)) > 1)
|
||||
pdgui_setsock(myportno);
|
||||
tk_myinterp = interp;
|
||||
pdgui_startup(interp);
|
||||
interp->result = "loaded pdtcl_init";
|
||||
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
int Pdtcl_SafeInit(Tcl_Interp *interp) {
|
||||
fprintf(stderr, "Pdtcl_Safeinit 51\n");
|
||||
return (TCL_OK);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,326 +0,0 @@
|
|||
/* Copyright (c) 2000 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
|
||||
|
||||
/* the "pdreceive" command. This is a standalone program that receives messages
|
||||
from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
|
||||
standard output. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef UNIX
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define SOCKET_ERROR -1
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
typedef struct _fdpoll
|
||||
{
|
||||
int fdp_fd;
|
||||
char *fdp_inbuf;
|
||||
int fdp_inhead;
|
||||
int fdp_intail;
|
||||
int fdp_udp;
|
||||
} t_fdpoll;
|
||||
|
||||
static int nfdpoll;
|
||||
static t_fdpoll *fdpoll;
|
||||
static int maxfd;
|
||||
static int sockfd;
|
||||
static int protocol;
|
||||
|
||||
static void sockerror(char *s);
|
||||
static void x_closesocket(int fd);
|
||||
static void dopoll(void);
|
||||
#define BUFSIZE 4096
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int portno;
|
||||
struct sockaddr_in server;
|
||||
int nretry = 10;
|
||||
#ifdef MSW
|
||||
short version = MAKEWORD(2, 0);
|
||||
WSADATA nobby;
|
||||
#endif
|
||||
if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
|
||||
goto usage;
|
||||
if (argc >= 3)
|
||||
{
|
||||
if (!strcmp(argv[2], "tcp"))
|
||||
protocol = SOCK_STREAM;
|
||||
else if (!strcmp(argv[2], "udp"))
|
||||
protocol = SOCK_DGRAM;
|
||||
else goto usage;
|
||||
}
|
||||
else protocol = SOCK_STREAM;
|
||||
#ifdef MSW
|
||||
if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
|
||||
#endif
|
||||
sockfd = socket(AF_INET, protocol, 0);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
sockerror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
maxfd = sockfd + 1;
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
#ifdef IRIX
|
||||
/* this seems to work only in IRIX but is unnecessary in
|
||||
Linux. Not sure what MSW needs in place of this. */
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
|
||||
post("setsockopt failed\n");
|
||||
#endif
|
||||
|
||||
/* assign client port number */
|
||||
server.sin_port = htons((unsigned short)portno);
|
||||
|
||||
/* name the socket */
|
||||
if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
|
||||
{
|
||||
sockerror("bind");
|
||||
x_closesocket(sockfd);
|
||||
return (0);
|
||||
}
|
||||
if (protocol == SOCK_STREAM)
|
||||
{
|
||||
if (listen(sockfd, 5) < 0)
|
||||
{
|
||||
sockerror("listen");
|
||||
x_closesocket(sockfd);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* now loop forever selecting on sockets */
|
||||
while (1)
|
||||
dopoll();
|
||||
|
||||
usage:
|
||||
fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
|
||||
fprintf(stderr, "(default is tcp)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void addport(int fd)
|
||||
{
|
||||
int nfd = nfdpoll;
|
||||
t_fdpoll *fp;
|
||||
fdpoll = (t_fdpoll *)realloc(fdpoll,
|
||||
(nfdpoll+1) * sizeof(t_fdpoll));
|
||||
fp = fdpoll + nfdpoll;
|
||||
fp->fdp_fd = fd;
|
||||
nfdpoll++;
|
||||
if (fd >= maxfd) maxfd = fd + 1;
|
||||
fp->fdp_inhead = fp->fdp_intail = 0;
|
||||
if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
|
||||
{
|
||||
fprintf(stderr, "out of memory");
|
||||
exit(1);
|
||||
}
|
||||
printf("number_connected %d;\n", nfdpoll);
|
||||
}
|
||||
|
||||
static void rmport(t_fdpoll *x)
|
||||
{
|
||||
int nfd = nfdpoll;
|
||||
int i, size = nfdpoll * sizeof(t_fdpoll);
|
||||
t_fdpoll *fp;
|
||||
for (i = nfdpoll, fp = fdpoll; i--; fp++)
|
||||
{
|
||||
if (fp == x)
|
||||
{
|
||||
x_closesocket(fp->fdp_fd);
|
||||
free(fp->fdp_inbuf);
|
||||
while (i--)
|
||||
{
|
||||
fp[0] = fp[1];
|
||||
fp++;
|
||||
}
|
||||
fdpoll = (t_fdpoll *)realloc(fdpoll,
|
||||
(nfdpoll-1) * sizeof(t_fdpoll));
|
||||
nfdpoll--;
|
||||
printf("number_connected %d;\n", nfdpoll);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "warning: item removed from poll list but not found");
|
||||
}
|
||||
|
||||
static void doconnect(void)
|
||||
{
|
||||
int fd = accept(sockfd, 0, 0);
|
||||
if (fd < 0)
|
||||
perror("accept");
|
||||
else addport(fd);
|
||||
}
|
||||
|
||||
static void udpread(void)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
int ret = recv(sockfd, buf, BUFSIZE, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
sockerror("recv (udp)");
|
||||
x_closesocket(sockfd);
|
||||
exit(1);
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
#ifdef UNIX
|
||||
if (write(1, buf, ret) < ret)
|
||||
{
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
int j;
|
||||
for (j = 0; j < ret; j++)
|
||||
putchar(buf[j]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int tcpmakeoutput(t_fdpoll *x)
|
||||
{
|
||||
char messbuf[BUFSIZE+1], *bp = messbuf;
|
||||
int indx;
|
||||
int inhead = x->fdp_inhead;
|
||||
int intail = x->fdp_intail;
|
||||
char *inbuf = x->fdp_inbuf;
|
||||
if (intail == inhead)
|
||||
return (0);
|
||||
for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
|
||||
{
|
||||
/* search for a semicolon. */
|
||||
char c = *bp++ = inbuf[indx];
|
||||
if (c == ';')
|
||||
{
|
||||
intail = (indx+1)&(BUFSIZE-1);
|
||||
if (inbuf[intail] == '\n')
|
||||
intail = (intail+1)&(BUFSIZE-1);
|
||||
*bp++ = '\n';
|
||||
#ifdef UNIX
|
||||
write(1, messbuf, bp - messbuf);
|
||||
#else
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < bp - messbuf; j++)
|
||||
putchar(messbuf[j]);
|
||||
}
|
||||
#endif
|
||||
x->fdp_inhead = inhead;
|
||||
x->fdp_intail = intail;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void tcpread(t_fdpoll *x)
|
||||
{
|
||||
int readto =
|
||||
(x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
|
||||
int ret;
|
||||
|
||||
/* the input buffer might be full. If so, drop the whole thing */
|
||||
if (readto == x->fdp_inhead)
|
||||
{
|
||||
fprintf(stderr, "pd: dropped message from gui\n");
|
||||
x->fdp_inhead = x->fdp_intail = 0;
|
||||
readto = BUFSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
|
||||
readto - x->fdp_inhead, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
sockerror("recv (tcp)");
|
||||
rmport(x);
|
||||
}
|
||||
else if (ret == 0)
|
||||
rmport(x);
|
||||
else
|
||||
{
|
||||
x->fdp_inhead += ret;
|
||||
if (x->fdp_inhead >= BUFSIZE)
|
||||
x->fdp_inhead = 0;
|
||||
while (tcpmakeoutput(x))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dopoll(void)
|
||||
{
|
||||
int i;
|
||||
t_fdpoll *fp;
|
||||
fd_set readset, writeset, exceptset;
|
||||
FD_ZERO(&writeset);
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&exceptset);
|
||||
|
||||
FD_SET(sockfd, &readset);
|
||||
if (protocol == SOCK_STREAM)
|
||||
{
|
||||
for (fp = fdpoll, i = nfdpoll; i--; fp++)
|
||||
FD_SET(fp->fdp_fd, &readset);
|
||||
}
|
||||
if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
|
||||
{
|
||||
perror("select");
|
||||
exit(1);
|
||||
}
|
||||
if (protocol == SOCK_STREAM)
|
||||
{
|
||||
for (i = 0; i < nfdpoll; i++)
|
||||
if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
|
||||
tcpread(&fdpoll[i]);
|
||||
if (FD_ISSET(sockfd, &readset))
|
||||
doconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FD_ISSET(sockfd, &readset))
|
||||
udpread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sockerror(char *s)
|
||||
{
|
||||
#ifdef MSW
|
||||
int err = WSAGetLastError();
|
||||
if (err == 10054) return;
|
||||
else if (err == 10044)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Warning: you might not have TCP/IP \"networking\" turned on\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
int err = errno;
|
||||
#endif
|
||||
fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
|
||||
}
|
||||
|
||||
static void x_closesocket(int fd)
|
||||
{
|
||||
#ifdef UNIX
|
||||
close(fd);
|
||||
#endif
|
||||
#ifdef MSW
|
||||
closesocket(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/* Copyright (c) 2000 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
|
||||
|
||||
/* the "pdsend" command. This is a standalone program that forwards messages
|
||||
from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define SOCKET_ERROR -1
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
void sockerror(char *s);
|
||||
void x_closesocket(int fd);
|
||||
#define BUFSIZE 4096
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sockfd, portno, protocol;
|
||||
struct sockaddr_in server;
|
||||
struct hostent *hp;
|
||||
char *hostname;
|
||||
int nretry = 10;
|
||||
#ifdef MSW
|
||||
short version = MAKEWORD(2, 0);
|
||||
WSADATA nobby;
|
||||
#endif
|
||||
if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
|
||||
goto usage;
|
||||
if (argc >= 3)
|
||||
hostname = argv[2];
|
||||
else hostname = "127.0.0.1";
|
||||
if (argc >= 4)
|
||||
{
|
||||
if (!strcmp(argv[3], "tcp"))
|
||||
protocol = SOCK_STREAM;
|
||||
else if (!strcmp(argv[3], "udp"))
|
||||
protocol = SOCK_DGRAM;
|
||||
else goto usage;
|
||||
}
|
||||
else protocol = SOCK_STREAM;
|
||||
#ifdef MSW
|
||||
if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
|
||||
#endif
|
||||
|
||||
sockfd = socket(AF_INET, protocol, 0);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
sockerror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
/* connect socket using hostname provided in command line */
|
||||
server.sin_family = AF_INET;
|
||||
hp = gethostbyname(hostname);
|
||||
if (hp == 0)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown host\n", hostname);
|
||||
x_closesocket(sockfd);
|
||||
exit(1);
|
||||
}
|
||||
memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
|
||||
|
||||
/* assign client port number */
|
||||
server.sin_port = htons((unsigned short)portno);
|
||||
|
||||
#if 0 /* try this again for 4.0; this crashed my RH 6.2 machine!) */
|
||||
|
||||
/* try to connect. */
|
||||
for (nretry = 0; nretry < (protocol == SOCK_STREAM ? 10 : 1); nretry++)
|
||||
|
||||
{
|
||||
if (nretry > 0)
|
||||
{
|
||||
sleep (nretry < 5 ? 1 : 5);
|
||||
fprintf(stderr, "retrying...");
|
||||
}
|
||||
if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
|
||||
goto connected;
|
||||
sockerror("connect");
|
||||
}
|
||||
x_closesocket(sockfd);
|
||||
exit(1);
|
||||
connected: ;
|
||||
#else
|
||||
/* try to connect. */
|
||||
if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
|
||||
{
|
||||
sockerror("connect");
|
||||
x_closesocket(sockfd);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
/* now loop reading stdin and sending it to socket */
|
||||
while (1)
|
||||
{
|
||||
char buf[BUFSIZE], *bp, nsent, nsend;
|
||||
if (!fgets(buf, BUFSIZE, stdin))
|
||||
break;
|
||||
nsend = strlen(buf);
|
||||
for (bp = buf, nsent = 0; nsent < nsend;)
|
||||
{
|
||||
int res = send(sockfd, buf, nsend-nsent, 0);
|
||||
if (res < 0)
|
||||
{
|
||||
sockerror("send");
|
||||
goto done;
|
||||
}
|
||||
nsent += res;
|
||||
bp += res;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (ferror(stdin))
|
||||
perror("stdin");
|
||||
exit (0);
|
||||
usage:
|
||||
fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
|
||||
fprintf(stderr, "(default is localhost and tcp)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void sockerror(char *s)
|
||||
{
|
||||
#ifdef MSW
|
||||
int err = WSAGetLastError();
|
||||
if (err == 10054) return;
|
||||
else if (err == 10044)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Warning: you might not have TCP/IP \"networking\" turned on\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
int err = errno;
|
||||
#endif
|
||||
fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
|
||||
}
|
||||
|
||||
void x_closesocket(int fd)
|
||||
{
|
||||
#ifdef UNIX
|
||||
close(fd);
|
||||
#endif
|
||||
#ifdef MSW
|
||||
closesocket(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
/* Copyright (c) 1997-2000 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* dialogs. LATER, deal with the situation where the object goes
|
||||
away before the panel does... */
|
||||
|
||||
#include "m_pd.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* --------------------- graphics responder ---------------- */
|
||||
|
||||
/* make one of these if you want to put up a dialog window but want to be
|
||||
protected from getting deleted and then having the dialog call you back. In
|
||||
this design the calling object doesn't have to keep the address of the dialog
|
||||
window around; instead we keep a list of all open dialogs. Any object that
|
||||
might have dialogs, when it is deleted, simply checks down the dialog window
|
||||
list and breaks off any dialogs that might later have sent messages to it.
|
||||
Only when the dialog window itself closes do we delete the gfxstub object. */
|
||||
|
||||
static t_class *gfxstub_class;
|
||||
|
||||
typedef struct _gfxstub
|
||||
{
|
||||
t_pd x_pd;
|
||||
t_pd *x_owner;
|
||||
void *x_key;
|
||||
t_symbol *x_sym;
|
||||
struct _gfxstub *x_next;
|
||||
} t_gfxstub;
|
||||
|
||||
static t_gfxstub *gfxstub_list;
|
||||
|
||||
/* create a new one. the "key" is an address by which the owner
|
||||
will identify it later; if the owner only wants one dialog, this
|
||||
could just be a pointer to the owner itself. The string "cmd"
|
||||
is a TK command to create the dialog, with "%s" embedded in
|
||||
it so we can provide a name by which the GUI can send us back
|
||||
messages; e.g., "pdtk_canvas_dofont %s 10". */
|
||||
|
||||
void gfxstub_new(t_pd *owner, void *key, const char *cmd)
|
||||
{
|
||||
char buf[MAXPDSTRING];
|
||||
char namebuf[80];
|
||||
t_gfxstub *x;
|
||||
t_symbol *s;
|
||||
/* if any exists with matching key, no need to make a
|
||||
new one; just tell tk to send it front. */
|
||||
for (x = gfxstub_list; x; x = x->x_next)
|
||||
{
|
||||
if (x->x_key == key)
|
||||
{
|
||||
sys_vgui("raise .gfxstub%x\n", x);
|
||||
sys_vgui("focus .gfxstub%x\n", x);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(cmd) + 84 > MAXPDSTRING)
|
||||
return;
|
||||
x = (t_gfxstub *)pd_new(gfxstub_class);
|
||||
sprintf(namebuf, ".gfxstub%x", (t_int)x);
|
||||
|
||||
s = gensym(namebuf);
|
||||
pd_bind(&x->x_pd, s);
|
||||
x->x_owner = owner;
|
||||
x->x_sym = s;
|
||||
x->x_key = key;
|
||||
x->x_next = gfxstub_list;
|
||||
gfxstub_list = x;
|
||||
sprintf(buf, cmd, s->s_name);
|
||||
sys_gui(buf);
|
||||
}
|
||||
|
||||
static void gfxstub_offlist(t_gfxstub *x)
|
||||
{
|
||||
t_gfxstub *y1, *y2;
|
||||
if (gfxstub_list == x)
|
||||
gfxstub_list = x->x_next;
|
||||
else for (y1 = gfxstub_list; y2 = y1->x_next; y1 = y2)
|
||||
if (y2 == x)
|
||||
{
|
||||
y1->x_next = y2->x_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the owner disappears, we still may have to stay around until our
|
||||
dialog window signs off. Anyway we can now tell the GUI to destroy the
|
||||
window. */
|
||||
void gfxstub_deleteforkey(void *key)
|
||||
{
|
||||
t_gfxstub *y;
|
||||
int didit = 1;
|
||||
while (didit)
|
||||
{
|
||||
didit = 0;
|
||||
for (y = gfxstub_list; y; y = y->x_next)
|
||||
{
|
||||
if (y->x_key == key)
|
||||
{
|
||||
sys_vgui("destroy .gfxstub%x\n", y);
|
||||
y->x_owner = 0;
|
||||
gfxstub_offlist(y);
|
||||
didit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- pd messages for gfxstub (these come from the GUI) ---------- */
|
||||
|
||||
/* "cancel" to request that we close the dialog window. */
|
||||
static void gfxstub_cancel(t_gfxstub *x)
|
||||
{
|
||||
gfxstub_deleteforkey(x->x_key);
|
||||
}
|
||||
|
||||
/* "signoff" comes from the GUI to say the dialog window closed. */
|
||||
static void gfxstub_signoff(t_gfxstub *x)
|
||||
{
|
||||
gfxstub_offlist(x);
|
||||
pd_free(&x->x_pd);
|
||||
}
|
||||
|
||||
static t_binbuf *gfxstub_binbuf;
|
||||
|
||||
/* a series of "data" messages rebuilds a scalar */
|
||||
static void gfxstub_data(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
if (!gfxstub_binbuf)
|
||||
gfxstub_binbuf = binbuf_new();
|
||||
binbuf_add(gfxstub_binbuf, argc, argv);
|
||||
binbuf_addsemi(gfxstub_binbuf);
|
||||
}
|
||||
/* the "end" message terminates rebuilding the scalar */
|
||||
static void gfxstub_end(t_gfxstub *x)
|
||||
{
|
||||
canvas_dataproperties((t_canvas *)x->x_owner,
|
||||
(t_scalar *)x->x_key, gfxstub_binbuf);
|
||||
binbuf_free(gfxstub_binbuf);
|
||||
gfxstub_binbuf = 0;
|
||||
}
|
||||
|
||||
/* anything else is a message from the dialog window to the owner;
|
||||
just forward it. */
|
||||
static void gfxstub_anything(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
if (x->x_owner)
|
||||
pd_typedmess(x->x_owner, s, argc, argv);
|
||||
}
|
||||
|
||||
static void gfxstub_free(t_gfxstub *x)
|
||||
{
|
||||
pd_unbind(&x->x_pd, x->x_sym);
|
||||
}
|
||||
|
||||
static void gfxstub_setup(void)
|
||||
{
|
||||
gfxstub_class = class_new(gensym("gfxstub"), (t_newmethod)gfxstub_new,
|
||||
(t_method)gfxstub_free,
|
||||
sizeof(t_gfxstub), CLASS_PD, 0);
|
||||
class_addanything(gfxstub_class, gfxstub_anything);
|
||||
class_addmethod(gfxstub_class, (t_method)gfxstub_signoff,
|
||||
gensym("signoff"), 0);
|
||||
class_addmethod(gfxstub_class, (t_method)gfxstub_data,
|
||||
gensym("data"), A_GIMME, 0);
|
||||
class_addmethod(gfxstub_class, (t_method)gfxstub_end,
|
||||
gensym("end"), 0);
|
||||
class_addmethod(gfxstub_class, (t_method)gfxstub_cancel,
|
||||
gensym("cancel"), 0);
|
||||
}
|
||||
|
||||
/* -------------------------- openpanel ------------------------------ */
|
||||
|
||||
static t_class *openpanel_class;
|
||||
|
||||
typedef struct _openpanel
|
||||
{
|
||||
t_object x_obj;
|
||||
t_symbol *x_s;
|
||||
} t_openpanel;
|
||||
|
||||
static void *openpanel_new(void)
|
||||
{
|
||||
char buf[50];
|
||||
t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
|
||||
sprintf(buf, "d%x", (t_int)x);
|
||||
x->x_s = gensym(buf);
|
||||
pd_bind(&x->x_obj.ob_pd, x->x_s);
|
||||
outlet_new(&x->x_obj, &s_symbol);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void openpanel_bang(t_openpanel *x)
|
||||
{
|
||||
sys_vgui("pdtk_openpanel %s\n", x->x_s->s_name);
|
||||
}
|
||||
|
||||
static void openpanel_symbol(t_openpanel *x, t_symbol *s)
|
||||
{
|
||||
outlet_symbol(x->x_obj.ob_outlet, s);
|
||||
}
|
||||
|
||||
static void openpanel_free(t_openpanel *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, x->x_s);
|
||||
}
|
||||
|
||||
static void openpanel_setup(void)
|
||||
{
|
||||
openpanel_class = class_new(gensym("openpanel"),
|
||||
(t_newmethod)openpanel_new, (t_method)openpanel_free,
|
||||
sizeof(t_openpanel), 0, A_DEFFLOAT, 0);
|
||||
class_addbang(openpanel_class, openpanel_bang);
|
||||
class_addsymbol(openpanel_class, openpanel_symbol);
|
||||
}
|
||||
|
||||
/* -------------------------- savepanel ------------------------------ */
|
||||
|
||||
static t_class *savepanel_class;
|
||||
|
||||
typedef struct _savepanel
|
||||
{
|
||||
t_object x_obj;
|
||||
t_symbol *x_s;
|
||||
} t_savepanel;
|
||||
|
||||
static void *savepanel_new(void)
|
||||
{
|
||||
char buf[50];
|
||||
t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
|
||||
sprintf(buf, "d%x", (t_int)x);
|
||||
x->x_s = gensym(buf);
|
||||
pd_bind(&x->x_obj.ob_pd, x->x_s);
|
||||
outlet_new(&x->x_obj, &s_symbol);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void savepanel_bang(t_savepanel *x)
|
||||
{
|
||||
sys_vgui("pdtk_savepanel %s\n", x->x_s->s_name);
|
||||
}
|
||||
|
||||
static void savepanel_symbol(t_savepanel *x, t_symbol *s)
|
||||
{
|
||||
outlet_symbol(x->x_obj.ob_outlet, s);
|
||||
}
|
||||
|
||||
static void savepanel_free(t_savepanel *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, x->x_s);
|
||||
}
|
||||
|
||||
static void savepanel_setup(void)
|
||||
{
|
||||
savepanel_class = class_new(gensym("savepanel"),
|
||||
(t_newmethod)savepanel_new, (t_method)savepanel_free,
|
||||
sizeof(t_savepanel), 0, A_DEFFLOAT, 0);
|
||||
class_addbang(savepanel_class, savepanel_bang);
|
||||
class_addsymbol(savepanel_class, savepanel_symbol);
|
||||
}
|
||||
|
||||
/* ---------------------- key and its relatives ------------------ */
|
||||
|
||||
static t_symbol *key_sym, *keyup_sym, *keyname_sym;
|
||||
static t_class *key_class, *keyup_class, *keyname_class;
|
||||
|
||||
typedef struct _key
|
||||
{
|
||||
t_object x_obj;
|
||||
} t_key;
|
||||
|
||||
static void *key_new( void)
|
||||
{
|
||||
t_key *x = (t_key *)pd_new(key_class);
|
||||
outlet_new(&x->x_obj, &s_float);
|
||||
pd_bind(&x->x_obj.ob_pd, key_sym);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void key_float(t_key *x, t_floatarg f)
|
||||
{
|
||||
outlet_float(x->x_obj.ob_outlet, f);
|
||||
}
|
||||
|
||||
static void key_free(t_key *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, key_sym);
|
||||
}
|
||||
|
||||
typedef struct _keyup
|
||||
{
|
||||
t_object x_obj;
|
||||
} t_keyup;
|
||||
|
||||
static void *keyup_new( void)
|
||||
{
|
||||
t_keyup *x = (t_keyup *)pd_new(keyup_class);
|
||||
outlet_new(&x->x_obj, &s_float);
|
||||
pd_bind(&x->x_obj.ob_pd, keyup_sym);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void keyup_float(t_keyup *x, t_floatarg f)
|
||||
{
|
||||
outlet_float(x->x_obj.ob_outlet, f);
|
||||
}
|
||||
|
||||
static void keyup_free(t_keyup *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, keyup_sym);
|
||||
}
|
||||
|
||||
typedef struct _keyname
|
||||
{
|
||||
t_object x_obj;
|
||||
t_outlet *x_outlet1;
|
||||
t_outlet *x_outlet2;
|
||||
} t_keyname;
|
||||
|
||||
static void *keyname_new( void)
|
||||
{
|
||||
t_keyname *x = (t_keyname *)pd_new(keyname_class);
|
||||
x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
|
||||
x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
|
||||
pd_bind(&x->x_obj.ob_pd, keyname_sym);
|
||||
return (x);
|
||||
}
|
||||
|
||||
static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av)
|
||||
{
|
||||
outlet_symbol(x->x_outlet2, atom_getsymbolarg(1, ac, av));
|
||||
outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
|
||||
}
|
||||
|
||||
static void keyname_free(t_keyname *x)
|
||||
{
|
||||
pd_unbind(&x->x_obj.ob_pd, keyname_sym);
|
||||
}
|
||||
|
||||
static void key_setup(void)
|
||||
{
|
||||
key_class = class_new(gensym("key"),
|
||||
(t_newmethod)key_new, (t_method)key_free,
|
||||
sizeof(t_key), CLASS_NOINLET, 0);
|
||||
class_addfloat(key_class, key_float);
|
||||
key_sym = gensym("#key");
|
||||
|
||||
keyup_class = class_new(gensym("keyup"),
|
||||
(t_newmethod)keyup_new, (t_method)keyup_free,
|
||||
sizeof(t_keyup), CLASS_NOINLET, 0);
|
||||
class_addfloat(keyup_class, keyup_float);
|
||||
keyup_sym = gensym("#keyup");
|
||||
class_sethelpsymbol(keyup_class, gensym("key"));
|
||||
|
||||
keyname_class = class_new(gensym("keyname"),
|
||||
(t_newmethod)keyname_new, (t_method)keyname_free,
|
||||
sizeof(t_keyname), CLASS_NOINLET, 0);
|
||||
class_addlist(keyname_class, keyname_list);
|
||||
keyname_sym = gensym("#keyname");
|
||||
class_sethelpsymbol(keyname_class, gensym("key"));
|
||||
}
|
||||
|
||||
/* -------------------------- setup routine ------------------------------ */
|
||||
|
||||
void x_gui_setup(void)
|
||||
{
|
||||
gfxstub_setup();
|
||||
openpanel_setup();
|
||||
savepanel_setup();
|
||||
key_setup();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,12 +3,21 @@ pdbox-net.c
|
|||
pdbox-func.c
|
||||
pdbox-gui.c
|
||||
|
||||
/*
|
||||
wfirstfit.c
|
||||
*/
|
||||
|
||||
PDa/src/s_audio_rockbox.c
|
||||
|
||||
PDa/src/d_ugen.c
|
||||
PDa/src/d_arithmetic.c
|
||||
PDa/src/d_dac.c
|
||||
PDa/src/d_misc.c
|
||||
PDa/src/d_fft.c
|
||||
PDa/src/d_imayer_fft.c
|
||||
PDa/src/d_mayer_fft.c
|
||||
PDa/src/d_fftroutine.c
|
||||
PDa/src/d_global.c
|
||||
PDa/src/d_resample.c
|
||||
PDa/src/d_ctl.c
|
||||
PDa/src/d_soundfile.c
|
||||
|
||||
PDa/src/g_canvas.c
|
||||
PDa/src/g_graph.c
|
||||
PDa/src/g_text.c
|
||||
|
|
@ -31,57 +40,32 @@ PDa/src/g_toggle.c
|
|||
PDa/src/g_vdial.c
|
||||
PDa/src/g_vslider.c
|
||||
PDa/src/g_vumeter.c
|
||||
|
||||
PDa/src/m_pd.c
|
||||
PDa/src/m_class.c
|
||||
PDa/src/m_obj.c
|
||||
PDa/src/m_atom.c
|
||||
PDa/src/m_memory.c
|
||||
|
||||
PDa/src/m_binbuf.c
|
||||
PDa/src/m_conf.c
|
||||
PDa/src/m_glob.c
|
||||
PDa/src/m_sched.c
|
||||
/* PDa/src/s_main.c Does not compile, system reasons */
|
||||
/* PDa/src/s_inter.c Does not compile, BSD sockets */
|
||||
PDa/src/m_fixed.c
|
||||
|
||||
PDa/src/s_file.c
|
||||
PDa/src/s_print.c
|
||||
PDa/src/s_loader.c
|
||||
PDa/src/s_path.c
|
||||
/*
|
||||
PDa/src/s_entry.c
|
||||
*/
|
||||
PDa/src/s_audio.c
|
||||
/*
|
||||
PDa/src/s_midi.c
|
||||
*/
|
||||
PDa/src/d_ugen.c
|
||||
PDa/src/d_arithmetic.c
|
||||
PDa/src/d_dac.c
|
||||
PDa/src/d_misc.c
|
||||
PDa/src/d_fft.c
|
||||
PDa/src/d_mayer_fft.c
|
||||
PDa/src/d_fftroutine.c
|
||||
PDa/src/d_global.c
|
||||
PDa/src/d_resample.c
|
||||
PDa/src/d_ctl.c
|
||||
PDa/src/d_soundfile.c
|
||||
|
||||
PDa/src/x_arithmetic.c
|
||||
PDa/src/x_connective.c
|
||||
PDa/src/x_interface.c
|
||||
/*
|
||||
PDa/src/x_midi.c
|
||||
*/
|
||||
PDa/src/x_misc.c
|
||||
PDa/src/x_time.c
|
||||
PDa/src/x_acoustics.c
|
||||
PDa/src/x_net.c
|
||||
PDa/src/x_qlist.c
|
||||
/*
|
||||
PDa/src/x_gui.c
|
||||
*/
|
||||
|
||||
PDa/src/d_imayer_fft.c
|
||||
PDa/src/m_fixed.c
|
||||
|
||||
PDa/intern/biquad~.c
|
||||
PDa/intern/bp~.c
|
||||
|
|
@ -109,9 +93,6 @@ PDa/intern/rsqrt~.c
|
|||
PDa/intern/samphold~.c
|
||||
PDa/intern/sfread~.c
|
||||
PDa/intern/sfwrite~.c
|
||||
/*
|
||||
PDa/intern/sig~.c
|
||||
*/
|
||||
PDa/intern/snapshot~.c
|
||||
PDa/intern/sqrt~.c
|
||||
PDa/intern/tabosc4~.c
|
||||
|
|
@ -130,9 +111,7 @@ PDa/intern/vline~.c
|
|||
PDa/intern/vsnapshot~.c
|
||||
PDa/intern/wrap~.c
|
||||
|
||||
/* PDa/extra/OSCroute.c */
|
||||
PDa/extra/bandpass.c
|
||||
/* PDa/extra/dumpOSC.c Does not compile, file handling stuff */
|
||||
PDa/extra/equalizer.c
|
||||
PDa/extra/gcanvas.c
|
||||
PDa/extra/highpass.c
|
||||
|
|
@ -143,10 +122,4 @@ PDa/extra/lowpass.c
|
|||
PDa/extra/lowshelf.c
|
||||
PDa/extra/moog~.c
|
||||
PDa/extra/notch.c
|
||||
/* PDa/extra/sendOSC.c Does not compile, file handling stuff */
|
||||
/*
|
||||
PDa/extra/shell.c
|
||||
PDa/extra/slider.c
|
||||
PDa/extra/sliderh.c
|
||||
*/
|
||||
PDa/extra/zerox~.c
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue