Commit b45ccdd5 authored by Cyril Deguet's avatar Cyril Deguet

* all: first implementation of a MilkDrop-compatible visualization plugin,

    based on ProjectM (xmms-projectm.sourceforge.net), without the
    dependency on SDL 1.3. At the moment it only works on X11 with GLX 1.3,
    I didn't manage to have it working with the 1.2 API :(
    SGI Pbuffers are not used yet, I didn't manage to have them working
    well either :(
    Milkdrop presets are searched in /etc/projectM/presets (guess why ;)
    With projectM presets, colours look a bit "flashy", I wonder if it
    is normal...
    To compile the plugin, add --enable-galaktos in configure. The only
    dependencies are on X11 and OpenGL libs.
    Enjoy !
parent 918eef52
......@@ -3,4 +3,23 @@ SOURCES_galaktos = plugin.c \
glx.c \
glx.h \
main.c \
main.h
main.h \
preset.c \
preset.h \
beat_detect.c \
param.c \
engine_vars.c \
parser.c \
builtin_funcs.c \
eval.c \
init_cond.c \
PCM.c \
fftsg.c \
per_frame_eqn.c \
splaytree.c \
custom_shape.c \
func.c \
per_pixel_eqn.c \
tree_types.c \
custom_wave.c \
video_init.c
/*****************************************************************************
* PCM.c:
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id$
*
* Authors: Cyril Deguet <asmax@videolan.org>
* code from projectM http://xmms-projectm.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
//PCM.c - Sound data handler
//
//by Peter Sperl
//
//Takes sound data from wherever and hands it back out.
//Returns PCM Data or spectrum data, or the derivative of the PCM data
#include <stdlib.h>
#include <stdio.h>
double **PCMd; //data structure to store PCM data PCM[channels][maxsamples]
int maxsamples; //size of PCM buffer
int start; //where to add data next
int *ip; //working space for FFT routines
double *w; //lookup table for FFT routines
int new; //how many new samples
//initPCM(int samples)
//
//Initializes the PCM buffer to
// number of samples specified.
void initPCM(int samples)
{
int i;
//Allocate memory for PCM data buffer
PCMd = (double **)malloc(2 * sizeof(double *));
PCMd[0] = (double *)malloc(samples * sizeof(double));
PCMd[1] = (double *)malloc(samples * sizeof(double));
maxsamples=samples;
new=0;
//Initialize buffers to 0
for (i=0;i<samples;i++)
{
PCMd[0][i]=0;
PCMd[1][i]=0;
}
start=0;
//Allocate FFT workspace
w= (double *)malloc(maxsamples*sizeof(double));
ip= (int *)malloc(maxsamples*sizeof(int));
ip[0]=0;
}
//The only current addPCM function, can support more
//
//Takes in a 2x512 array of PCM samples
//and stores them
void addPCM(int16_t PCMdata[2][512])
{
int i,j;
int samples=512;
for(i=0;i<samples;i++)
{
j=i+start;
PCMd[0][j%maxsamples]=(PCMdata[0][i]/16384.0);
PCMd[1][j%maxsamples]=(PCMdata[1][i]/16384.0);
}
// printf("Added %d samples %d %d %f\n",samples,start,(start+samples)%maxsamples,PCM[0][start+10]);
start+=samples;
start=start%maxsamples;
new+=samples;
if (new>maxsamples) new=maxsamples;
}
//puts sound data requested at provided pointer
//
//samples is number of PCM samples to return
//freq = 0 gives PCM data
//freq = 1 gives FFT data
//smoothing is the smoothing coefficient
//returned values are normalized from -1 to 1
void getPCM(double *PCMdata, int samples, int channel, int freq, double smoothing, int derive)
{
int i,index;
index=start-1;
if (index<0) index=maxsamples+index;
PCMdata[0]=PCMd[channel][index];
for(i=1;i<samples;i++)
{
index=start-1-i;
if (index<0) index=maxsamples+index;
PCMdata[i]=(1-smoothing)*PCMd[channel][index]+smoothing*PCMdata[i-1];
}
//return derivative of PCM data
if(derive)
{
for(i=0;i<samples-1;i++)
{
PCMdata[i]=PCMdata[i]-PCMdata[i+1];
}
PCMdata[samples-1]=0;
}
//return frequency data instead of PCM (perform FFT)
if (freq) rdft(samples, 1, PCMdata, ip, w);
}
//getPCMnew
//
//Like getPCM except it returns all new samples in the buffer
//the actual return value is the number of samples, up to maxsamples.
//the passed pointer, PCMData, must bee able to hold up to maxsamples
int getPCMnew(double *PCMdata, int channel, int freq, double smoothing, int derive, int reset)
{
int i,index;
index=start-1;
if (index<0) index=maxsamples+index;
PCMdata[0]=PCMd[channel][index];
for(i=1;i<new;i++)
{
index=start-1-i;
if (index<0) index=maxsamples+index;
PCMdata[i]=(1-smoothing)*PCMd[channel][index]+smoothing*PCMdata[i-1];
}
//return derivative of PCM data
if(derive)
{
for(i=0;i<new-1;i++)
{
PCMdata[i]=PCMdata[i]-PCMdata[i+1];
}
PCMdata[new-1]=0;
}
//return frequency data instead of PCM (perform FFT)
// if (freq) rdft(samples, 1, PCMdata, ip, w);
i=new;
if (reset) new=0;
return i;
}
//Free stuff
void freePCM()
{
free(PCMd[0]);
free(PCMd[1]);
free(PCMd);
free(ip);
free(w);
}
void initPCM(int maxsamples);
void addPCM(int16_t [2][512]);
void getPCM(double *data, int samples, int channel, int freq, double smoothing, int derive);
void freePCM();
int getPCMnew(double *PCMdata, int channel, int freq, double smoothing, int derive,int reset);
/*****************************************************************************
* beat_detect.c: basic beat detection algorithm
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id$
*
* Authors: Cyril Deguet <asmax@videolan.org>
* code from projectM http://xmms-projectm.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
//
//by Peter Sperl
//
//Takes sound data from wherever and returns beat detection values
//Uses statistical Energy-Based methods. Very simple
//
//Some stuff was taken from Frederic Patin's beat-detection article, you'll find it online
#include <stdlib.h>
#include <stdio.h>
#include "engine_vars.h"
double beat_buffer[32][80],beat_instant[32],beat_history[32];
double *beat_val,*beat_att,*beat_variance;
int beat_buffer_pos;
double vol_buffer[80],vol_instant,vol_history;
void initBeatDetect()
{
int x,y;
vol_instant=0;
vol_history=0;
for (y=0;y<80;y++)
{
vol_buffer[y]=0;
}
beat_buffer_pos=0;
beat_val=(double *)malloc(32*sizeof(double));
beat_att=(double *)malloc(32*sizeof(double));
beat_variance=(double *)malloc(32*sizeof(double));
for (x=0;x<32;x++)
{
beat_instant[x]=0;
beat_history[x]=0;
beat_val[x]=1.0;
beat_att[x]=1.0;
beat_variance[x]=0;
for (y=0;y<80;y++)
{
beat_buffer[x][y]=0;
}
}
}
void getBeatVals(double *vdataL,double *vdataR, double *vol)
{
int linear=0;
int x,y;
vol_instant=0;
for ( x=0;x<16;x++)
{
beat_instant[x]=0;
for ( y=linear*2;y<(linear+8+x)*2;y++)
{
beat_instant[x]+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/(8+x));
vol_instant+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/512.0);
}
linear=y/2;
beat_history[x]-=(beat_buffer[x][beat_buffer_pos])*.0125;
beat_buffer[x][beat_buffer_pos]=beat_instant[x];
beat_history[x]+=(beat_instant[x])*.0125;
beat_val[x]=(beat_instant[x])/(beat_history[x]);
beat_att[x]+=(beat_instant[x])/(beat_history[x]);
}
vol_history-=(vol_buffer[beat_buffer_pos])*.0125;
vol_buffer[beat_buffer_pos]=vol_instant;
vol_history+=(vol_instant)*.0125;
double temp2=0;
mid=0;
for(x=1;x<10;x++)
{
mid+=(beat_instant[x]);
temp2+=(beat_history[x]);
}
mid=mid/(1.5*temp2);
temp2=0;
treb=0;
for(x=10;x<16;x++)
{
treb+=(beat_instant[x]);
temp2+=(beat_history[x]);
}
treb=treb/(1.5*temp2);
*vol=vol_instant/(1.5*vol_history);
bass=(beat_instant[0])/(1.5*beat_history[0]);
treb_att=.6 * treb_att + .4 * treb;
mid_att=.6 * mid_att + .4 * mid;
bass_att=.6 * bass_att + .4 * bass;
//printf("%f %f %f %f\n",bass,mid,treb,*vol);
// *vol=(beat_instant[3])/(beat_history[3]);
beat_buffer_pos++;
if( beat_buffer_pos>79)beat_buffer_pos=0;
}
void freeBeatDetect()
{
free(beat_att);
free(beat_val);
free(beat_variance);
}
void initBeatDetect();
void getBeatVals(double *vdataL,double *vdataR,double *vol);
void freeBeatDetect();
/*****************************************************************************
* builtin_funcs.c:
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id$
*
* Authors: Cyril Deguet <asmax@videolan.org>
* code from projectM http://xmms-projectm.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
/* Values to optimize the sigmoid function */
#define R 32767
#define RR 65534
inline double int_wrapper(double * arg_list) {
return floor(arg_list[0]);
}
inline double sqr_wrapper(double * arg_list) {
return pow(2, arg_list[0]);
}
inline double sign_wrapper(double * arg_list) {
return -arg_list[0];
}
inline double min_wrapper(double * arg_list) {
if (arg_list[0] > arg_list[1])
return arg_list[1];
return arg_list[0];
}
inline double max_wrapper(double * arg_list) {
if (arg_list[0] > arg_list[1])
return arg_list[0];
return arg_list[1];
}
/* consult your AI book */
inline double sigmoid_wrapper(double * arg_list) {
return (RR / (1 + exp( -(((double)(arg_list[0])) * arg_list[1]) / R) - R));
}
inline double bor_wrapper(double * arg_list) {
return (double)((int)arg_list[0] || (int)arg_list[1]);
}
inline double band_wrapper(double * arg_list) {
return (double)((int)arg_list[0] && (int)arg_list[1]);
}
inline double bnot_wrapper(double * arg_list) {
return (double)(!(int)arg_list[0]);
}
inline double if_wrapper(double * arg_list) {
if ((int)arg_list[0] == 0)
return arg_list[2];
return arg_list[1];
}
inline double rand_wrapper(double * arg_list) {
double l;
// printf("RAND ARG:(%d)\n", (int)arg_list[0]);
l = (double)((rand()) % ((int)arg_list[0]));
//printf("VAL: %f\n", l);
return l;
}
inline double equal_wrapper(double * arg_list) {
return (arg_list[0] == arg_list[1]);
}
inline double above_wrapper(double * arg_list) {
return (arg_list[0] > arg_list[1]);
}
inline double below_wrapper(double * arg_list) {
return (arg_list[0] < arg_list[1]);
}
inline double sin_wrapper(double * arg_list) {
return (sin (arg_list[0]));
}
inline double cos_wrapper(double * arg_list) {
return (cos (arg_list[0]));
}
inline double tan_wrapper(double * arg_list) {
return (tan(arg_list[0]));
}
inline double asin_wrapper(double * arg_list) {
return (asin (arg_list[0]));
}
inline double acos_wrapper(double * arg_list) {
return (acos (arg_list[0]));
}
inline double atan_wrapper(double * arg_list) {
return (atan (arg_list[0]));
}
inline double atan2_wrapper(double * arg_list) {
return (atan2 (arg_list[0], arg_list[1]));
}
inline double pow_wrapper(double * arg_list) {
return (pow (arg_list[0], arg_list[1]));
}
inline double exp_wrapper(double * arg_list) {
return (exp(arg_list[0]));
}
inline double abs_wrapper(double * arg_list) {
return (fabs(arg_list[0]));
}
inline double log_wrapper(double *arg_list) {
return (log (arg_list[0]));
}
inline double log10_wrapper(double * arg_list) {
return (log10 (arg_list[0]));
}
inline double sqrt_wrapper(double * arg_list) {
return (sqrt (arg_list[0]));
}
inline double nchoosek_wrapper(double * arg_list) {
unsigned long cnm = 1UL;
int i, f;
int n, m;
n = (int)arg_list[0];
m = (int)arg_list[1];
if (m*2 >n) m = n-m;
for (i=1 ; i <= m; n--, i++)
{
if ((f=n) % i == 0)
f /= i;
else cnm /= i;
cnm *= f;
}
return (double)cnm;
}
inline double fact_wrapper(double * arg_list) {
int result = 1;
int n = (int)arg_list[0];
while (n > 1) {
result = result * n;
n--;
}
return (double)result;
}
/* Wrappers for all the builtin functions
The arg_list pointer is a list of doubles. Its
size is equal to the number of arguments the parameter
takes */
inline double below_wrapper(double * arg_list);
inline double above_wrapper(double * arg_list);
inline double equal_wrapper(double * arg_list);
inline double if_wrapper(double * arg_list);
inline double bnot_wrapper(double * arg_list);
inline double rand_wrapper(double * arg_list);
inline double bor_wrapper(double * arg_list);
inline double band_wrapper(double * arg_list);
inline double sigmoid_wrapper(double * arg_list);
inline double max_wrapper(double * arg_list);
inline double min_wrapper(double * arg_list);
inline double sign_wrapper(double * arg_list);
inline double sqr_wrapper(double * arg_list);
inline double int_wrapper(double * arg_list);
inline double nchoosek_wrapper(double * arg_list);
inline double sin_wrapper(double * arg_list);
inline double cos_wrapper(double * arg_list);
inline double tan_wrapper(double * arg_list);
inline double fact_wrapper(double * arg_list);
inline double asin_wrapper(double * arg_list);
inline double acos_wrapper(double * arg_list);
inline double atan_wrapper(double * arg_list);
inline double atan2_wrapper(double * arg_list);
inline double pow_wrapper(double * arg_list);
inline double exp_wrapper(double * arg_list);
inline double abs_wrapper(double * arg_list);
inline double log_wrapper(double *arg_list);
inline double log10_wrapper(double * arg_list);
inline double sqrt_wrapper(double * arg_list);
#ifndef COMMON_H
#define COMMON_H
#define DEFAULT_FONT_PATH "/home/carm/fonts/courier1.glf"
#define MAX_TOKEN_SIZE 512
#define MAX_PATH_SIZE 4096
#define STRING_BUFFER_SIZE 1024*150
#define STRING_LINE_SIZE 1024
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define PROJECTM_FILE_EXTENSION ".prjm"
#define MILKDROP_FILE_EXTENSION ".milk"