|
|
|
/* Synaesthesia - program to display sound graphically
|
|
|
|
Copyright (C) 1997 Paul Francis Harrison
|
|
|
|
|
|
|
|
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.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
The author may be contacted at:
|
|
|
|
pfh@yoyo.cc.monash.edu.au
|
|
|
|
or
|
|
|
|
27 Bond St., Mt. Waverley, 3149, Melbourne, Australia
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(__linux__) || defined(__svr4__)
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#include <sys/sem.h>
|
|
|
|
#include <sys/shm.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#if defined (__linux__)
|
|
|
|
#include <linux/soundcard.h>
|
|
|
|
#ifndef __GNUC__
|
|
|
|
#define __GNUC__ 1
|
|
|
|
#endif
|
|
|
|
#undef __STRICT_ANSI__
|
|
|
|
#include <asm/types.h>
|
|
|
|
#include <linux/cdrom.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (__svr4__)
|
|
|
|
#include <sys/soundcard.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// who knows when we'll need that...
|
|
|
|
#if defined (FreeBSD)
|
|
|
|
#include <sys/soundcard.h>
|
|
|
|
#include <sys/cdio.h>
|
|
|
|
#define CDROM_LEADOUT 0xAA
|
|
|
|
#define CD_FRAMES 75 /* frames per second */
|
|
|
|
#define CDROM_DATA_TRACK 0x4
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "syna.h"
|
|
|
|
#include "magicconf.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* Sound Recording ================================================= */
|
|
|
|
|
|
|
|
#ifdef LITTLEENDIAN
|
|
|
|
#define SOUNDFORMAT AFMT_S16_LE
|
|
|
|
#else
|
|
|
|
#define SOUNDFORMAT AFMT_S16_BE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//If kernel starts running out of sound memory playing mp3s, this could
|
|
|
|
//be the problem. OTOH if it is too small, it will start ticking on slow
|
|
|
|
//computers
|
|
|
|
#define MAXWINDOWSIZE 32
|
|
|
|
|
|
|
|
static SoundSource source;
|
|
|
|
static int inFrequency, downFactor, windowSize, pipeIn, device;
|
|
|
|
static short *dataIn;
|
|
|
|
static char *mixer;
|
|
|
|
|
|
|
|
void
|
|
|
|
openSound(SoundSource source, int inFrequency, const char *dspName,
|
|
|
|
char *mixerName)
|
|
|
|
{
|
|
|
|
::source = source;
|
|
|
|
::inFrequency = inFrequency;
|
|
|
|
::windowSize = 1;
|
|
|
|
mixer = mixerName;
|
|
|
|
downFactor = inFrequency / frequency;
|
|
|
|
if (downFactor <= 0)
|
|
|
|
downFactor = 1;
|
|
|
|
|
|
|
|
int format, stereo, fragment, fqc;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
attempt(device = open(dspName,O_WRONLY),"opening dsp device",true);
|
|
|
|
format = SOUNDFORMAT;
|
|
|
|
attempt(ioctl(device,SNDCTL_DSP_SETFMT,&format),"setting format",true);
|
|
|
|
if (format != SOUNDFORMAT) error("setting format (2)");
|
|
|
|
close(device);
|
|
|
|
#endif
|
|
|
|
if (source == SourcePipe)
|
|
|
|
attempt(device = open(dspName,O_WRONLY),"opening dsp device",true);
|
|
|
|
else
|
|
|
|
attempt(device = open(dspName,O_RDONLY),"opening dsp device",true);
|
|
|
|
|
|
|
|
//Probably not needed
|
|
|
|
//attemptNoDie(ioctl(device,SNDCTL_DSP_RESET,0),"reseting dsp");
|
|
|
|
format = SOUNDFORMAT;
|
|
|
|
fqc = (source == SourcePipe ? inFrequency : frequency);
|
|
|
|
stereo = 1;
|
|
|
|
|
|
|
|
//int logWindowSize = -1, tmp = windowSize*downFactor;
|
|
|
|
//while(tmp) {
|
|
|
|
// tmp /= 2;
|
|
|
|
// logWindowSize++;
|
|
|
|
//}
|
|
|
|
|
|
|
|
if (source == SourcePipe)
|
|
|
|
//fragment = 0x00020000 + (m-overlap+1)+logWindowSize;
|
|
|
|
fragment = 0x00010000*(MAXWINDOWSIZE+1) + (m-overlap+1);//+logWindowSize;
|
|
|
|
//Soundcard should read in windowSize
|
|
|
|
// blocks of sound before blocking
|
|
|
|
else
|
|
|
|
//fragment = 0x00020000 + (m-overlap+1); //2 fragments of size 2*(2^(m-overlap+1)) bytes
|
|
|
|
|
|
|
|
//Added extra fragments to allow recording overrun (9/7/98)
|
|
|
|
fragment = 0x00080000 + (m-overlap+1); //8 fragments of size 2*(2^(m-overlap+1)) bytes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Was 0x00010000 + m;
|
|
|
|
|
|
|
|
attemptNoDie(ioctl(device,SNDCTL_DSP_SETFRAGMENT,&fragment),"setting fragment",true);
|
|
|
|
#ifndef __FreeBSD__
|
|
|
|
attempt(ioctl(device,SNDCTL_DSP_SETFMT,&format),"setting format",true);
|
|
|
|
if (format != SOUNDFORMAT) error("setting format (2)");
|
|
|
|
#endif
|
|
|
|
attempt(ioctl(device,SNDCTL_DSP_STEREO,&stereo),"setting stereo",true);
|
|
|
|
attemptNoDie(ioctl(device,SNDCTL_DSP_SPEED,&fqc),"setting frequency",true);
|
|
|
|
|
|
|
|
data = new short[n*2];
|
|
|
|
|
|
|
|
if (source == SourcePipe) {
|
|
|
|
dataIn = new short[n*2*downFactor*MAXWINDOWSIZE];
|
|
|
|
memset(dataIn,0,n*4*downFactor*MAXWINDOWSIZE);
|
|
|
|
pipeIn = dup(0);
|
|
|
|
close(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void closeSound() {
|
|
|
|
delete data;
|
|
|
|
if (source == SourcePipe) {
|
|
|
|
delete dataIn;
|
|
|
|
close(pipeIn);
|
|
|
|
}
|
|
|
|
close(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
int readWholeBlock(int pipe,char *dest,int length) {
|
|
|
|
while(length > 0) {
|
|
|
|
int result = read(pipe,dest,length);
|
|
|
|
if (result < 1)
|
|
|
|
return -1;
|
|
|
|
dest += result;
|
|
|
|
length -= result;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getNextFragment(void) {
|
|
|
|
if (source == SourcePipe) {
|
|
|
|
static int lastTime = 0;
|
|
|
|
int nowTime;
|
|
|
|
timeval timeVal1, timeVal2;
|
|
|
|
|
|
|
|
gettimeofday(&timeVal1,0);
|
|
|
|
write(device, (char*)dataIn, n*4*downFactor*windowSize);
|
|
|
|
gettimeofday(&timeVal2,0);
|
|
|
|
|
|
|
|
nowTime = timeVal1.tv_usec + timeVal1.tv_sec * 1000000;
|
|
|
|
if (nowTime > lastTime) {
|
|
|
|
int optimumFrags =
|
|
|
|
int(double(nowTime-lastTime)*inFrequency/1000000.0/(n*downFactor))
|
|
|
|
+1;
|
|
|
|
if (optimumFrags > MAXWINDOWSIZE)
|
|
|
|
optimumFrags = MAXWINDOWSIZE;
|
|
|
|
|
|
|
|
windowSize = optimumFrags;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastTime = timeVal2.tv_usec + timeVal2.tv_sec * 1000000;
|
|
|
|
|
|
|
|
if (readWholeBlock(pipeIn, ((char*)dataIn), n*4*downFactor*windowSize) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int i,j;
|
|
|
|
for(i=0,j=0;i<n;i++,j+=downFactor)
|
|
|
|
((long*)data)[i] = ((long*)dataIn)[j];
|
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
count_info info;
|
|
|
|
if (-1 == ioctl(device,SNDCTL_DSP_GETIPTR,&info))
|
|
|
|
info.blocks = 1;
|
|
|
|
if (info.blocks > 8 || info.blocks < 1) /* Sanity check */
|
|
|
|
info.blocks = 1;
|
|
|
|
|
|
|
|
for(i=0;i<info.blocks;i++) {
|
|
|
|
if (recSize != n)
|
|
|
|
memmove((char*)data,(char*)data+recSize*4,(n-recSize)*4);
|
|
|
|
|
|
|
|
attemptNoDie(
|
|
|
|
readWholeBlock(device,(char*)data+n*4-recSize*4, recSize*4),
|
|
|
|
"reading from soundcard", true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// generic dummy implementation
|
|
|
|
|
|
|
|
#include "syna.h"
|
|
|
|
|
|
|
|
int getNextFragment(void) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void openSound(SoundSource source, int inFrequency, const char *dspName,
|
|
|
|
char *mixerName)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void closeSound()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // linux || svr4
|
|
|
|
|