Mercurial > audlegacy-plugins
diff src/Visualization/paranormal/pn/pnscript.c @ 0:13389e613d67 trunk
[svn] - initial import of audacious-plugins tree (lots to do)
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 01:11:49 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Visualization/paranormal/pn/pnscript.c Mon Sep 18 01:11:49 2006 -0700 @@ -0,0 +1,285 @@ +/* Paranormal - A highly customizable audio visualization library + * Copyright (C) 2001 Jamie Gennis <jgennis@mindspring.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> + +#include <math.h> +#include "pnscript.h" + +/* Initialization */ +static void pn_script_class_init (PnScriptClass *class); + +/* Internal parser */ +gboolean pn_script_internal_parse_string (PnScript *script, + const gchar *string); + +static GObjectClass *parent_class = NULL; + +GType +pn_script_get_type (void) +{ + static GType script_type = 0; + + if (! script_type) + { + static const GTypeInfo script_info = + { + sizeof (PnScriptClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) pn_script_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PnScript), + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + + /* FIXME: should this be dynamic? */ + script_type = g_type_register_static (PN_TYPE_OBJECT, + "PnScript", + &script_info, + 0); + } + return script_type; +} + +static void +pn_script_class_init (PnScriptClass *class) +{ + GObjectClass *gobject_class; + PnObjectClass *object_class; + + gobject_class = (GObjectClass *) class; + object_class = (PnObjectClass *) class; + + parent_class = g_type_class_peek_parent (class); +} + +static void +pn_script_unref_variables (PnScript *script) +{ + g_return_if_fail (script != NULL); + g_return_if_fail (PN_IS_SCRIPT (script)); + + if (script->code && script->symbol_table) + { + guint *op; + + for (op = script->code; *op != PN_OP_END; op++) + switch (*op) + { + case PN_OP_PUSHC: + op++; + break; + + case PN_OP_PUSHV: + pn_symbol_table_unref_variable (script->symbol_table, PN_VARIABLE (*(++op))); + break; + + case PN_OP_SET: + pn_symbol_table_unref_variable (script->symbol_table, PN_VARIABLE (*(++op))); + break; + } + } +} + +/** + * pn_script_new + * + * Creates a new #PnScript object. + * + * Returns: The newly created #PnScript object + */ +PnScript* +pn_script_new (void) +{ + return (PnScript *) g_object_new (PN_TYPE_SCRIPT, NULL); +} + +/** + * pn_script_parse_string + * @script: A #PnScript + * @symbol_table: the #PnSymbolTable to associate with the script + * @string: a string containing the script + * + * Parses a script, compiling it to a bytecode that is stored within the script object. + * All in-script variables within the script are added to the specified symbol table (if + * they are not already in it). If errors are encountered while parsing the script, + * they are output using pn_error(). + * + * Returns: %TRUE on success; %FALSE otherwise + */ +gboolean +pn_script_parse_string (PnScript *script, PnSymbolTable *symbol_table, const gchar *string) +{ + g_return_val_if_fail (script != NULL, FALSE); + g_return_val_if_fail (PN_IS_SCRIPT (script), FALSE); + g_return_val_if_fail (symbol_table != NULL, FALSE); + g_return_val_if_fail (PN_IS_SYMBOL_TABLE (symbol_table), FALSE); + g_return_val_if_fail (string != NULL, FALSE); + + /* Make sure if it's the same symbol table, we don't destroy it */ + pn_object_ref (PN_OBJECT (symbol_table)); + pn_object_sink (PN_OBJECT (symbol_table)); + + /* get rid of the old script */ + if (script->symbol_table) + { + pn_script_unref_variables (script); + pn_object_unref (PN_OBJECT (script->symbol_table)); + } + if (script->stack) + { + g_free (script->stack); + script->stack = NULL; + } + if (script->code) + { + g_free (script->code); + script->code = NULL; + } + if (script->constant_table) + { + g_free (script->constant_table); + script->constant_table = NULL; + } + + /* Set our new symbol table */ + script->symbol_table = symbol_table; + + return pn_script_internal_parse_string (script, string); +} + +/** + * pn_script_execute + * @script: a #PnScript + * + * Executes a script, updating all variabes in the associated symbol + * table as the script dictates. + */ +void +pn_script_execute (PnScript *script) +{ + guint *op; + gdouble stack[64]; + guint stack_top = 0; + gdouble temp; + + g_return_if_fail (script != NULL); + g_return_if_fail (PN_IS_SCRIPT (script)); + + if (! script->code) + return; + + for (op = script->code; *op != PN_OP_END; op++) + switch (*op) + { +#define PUSH(f) stack[stack_top++] = f; +#define POP stack_top--; +#define POPV (stack[--stack_top]) +#define PEEK (stack[stack_top-1]) +#define PEEKN(n) (stack[stack_top-n]) + case PN_OP_PUSHC: + case PN_OP_PUSHV: + PUSH (* (gdouble *)(*(++op))); + break; + + case PN_OP_POP: + POP; + break; + + case PN_OP_SET: + *(gdouble *)(*(++op)) = PEEK; + break; + + case PN_OP_ADD: + /* PEEKN (2) += POPV; */ + temp = POPV; + PEEKN(1) += temp; + break; + + case PN_OP_SUB: + /* PEEKN (2) -= POPV; */ + temp = POPV; + PEEKN(1) -= temp; + break; + + case PN_OP_MUL: + /* PEEKN (2) *= POPV; */ + temp = POPV; + PEEKN(1) *= temp; + break; + + case PN_OP_DIV: + if (PEEK != 0) + PEEKN (2) /= PEEK; + else + PEEK = 0; + POP; + break; + + case PN_OP_NEG: + PEEK = -PEEK; + break; + + case PN_OP_POW: + PEEKN (2) = pow (PEEKN (2), PEEK); + POP; + break; + + case PN_OP_ABS: + PEEK = ABS (PEEK); + break; + + case PN_OP_MAX: + PEEKN (2) = MAX (PEEK, PEEKN (2)); + POP; + break; + + case PN_OP_MIN: + PEEKN (2) = MIN (PEEK, PEEKN (2)); + POP; + break; + + case PN_OP_SIN: + PEEK = sin (PEEK); + break; + + case PN_OP_COS: + PEEK = cos (PEEK); + break; + + case PN_OP_TAN: + PEEK = tan (PEEK); + break; + + case PN_OP_ASIN: + PEEK = asin (PEEK); + break; + + case PN_OP_ACOS: + PEEK = acos (PEEK); + break; + + case PN_OP_ATAN: + PEEK = atan (PEEK); + break; + } +} +