Commit b125d4a5 authored by Dr-Dan's avatar Dr-Dan

mfcc and all grains classes emscriptened. Grains examples added

parent 1d6e5d50
Maxi_Emscripten/
src/cpp/Maximilian-master/
Recordings/
\ No newline at end of file
Recordings/
maxiLib/maximilian_examples_web/load_sample_test.html
\ No newline at end of file
......@@ -17,9 +17,10 @@ OUTPUT_MAXI=maxiLib/maxiLib.js
# extra libs stuff
SOURCE_maxiFFT=src/cpp/libs/maxiFFT.cpp
SOURCE_maxiMFCC=src/cpp/libs/maxiMFCC.cpp
SOURCE_maxiGrains=src/cpp/libs/maxiGrains.cpp
# destination for maxiFFT from when I didn't know better
# OUTPUT_maxiFFT=maxiLib/libs/maxiLib_maxiFFT.js
SOURCES_LIBS = $(SOURCE_maxiFFT) $(SOURCE_maxiMFCC) $(SOURCE_maxiGrains)
# ----------------------------------------
......@@ -31,6 +32,6 @@ CFLAGS=-O3 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1 -s ASSERTION
# ----------------------------------------
# Final paths
maxi:
$(EMSCR) $(CFLAGS) --post-js $(POST_JS) --bind -o $(OUTPUT_MAXI) $(SOURCE_MAXI) $(SOURCE_maxiFFT)
$(EMSCR) $(CFLAGS) --post-js $(POST_JS) --bind -o $(OUTPUT_MAXI) $(SOURCE_MAXI) $(SOURCES_LIBS)
all: maxi
\ No newline at end of file
......@@ -12,9 +12,8 @@ natsort($phpfiles);
foreach($phpfiles as $phpfile)
{
echo "</br>";
echo "<a href=$phpfile>".basename($phpfile)."</a>";
echo "<a href=./$phpfile>".basename($phpfile)."</a>";
echo "\n</br>";
}
?>
</body>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<!--
Copyright 2010, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>
Javascript Audio Processing
</title>
<!-- <link rel="stylesheet" type="text/css" href="javascript-processing_files/simple.css"> -->
<script src="../maxiLib.js"></script>
<!-- Our javascript code -->
<script type="text/javascript">
var samplePlayer = new maximJs.maxiSample();
var grains = new Module.maxiTimestretch();
// var shift = new Module.maxiPitchShift();
// var stretch = new Module.maxiPitchStretch();
var speed = 0.5;
function setup(){
// console.log(samplePlayer.load("Macintosh HD/Users/Dan/Documents/Programming/Emscripten/emsdk_portable/emscripten/tag-1.34.11/tests/maximilian/web/maximilian_examples_web/beat2.wav", 1));
loadSample("./beat2.wav", samplePlayer);
}
var grainsSet = false;
function play(){
// this is necessary as file loading may not complete in setup
if(samplePlayer.isReady()){
// set grainPlayer sample
if(!grainsSet){
grains.setSample(samplePlayer);
// shift.setSample(samplePlayer);
// stretch.setSample(samplePlayer);
grainsSet = true;
}
output = grains.play(speed, 0.1, 4, 0);
// ouptut = grains.play2(pos, 0.1, 4);
}
}
</script>
</head>
<body>
<h1> Granular Synthesis Example </h1>
<p>
</p>
</body></html>
#include "maxiGrains.h"
#include "maxiGrains_embind.h"
......
......@@ -2,8 +2,7 @@
#ifndef _MAXI_GRAINS_H
#define _MAXI_GRAINS_H
#include "maximilian.h"
#include "../maxi_emscr_new.h"
#if defined(__APPLE_CC__)
#include "accelerate/accelerate.h"
//Mac users can uncommment the line below to use Apple's accelerate framework for calculating grains. This gives ~300% speed improvement and better sound quality, but doesn't work well on all machines.
......@@ -160,7 +159,8 @@ public:
*/
maxiGrain(maxiSample *sample, const double position, const double duration, const double speed, maxiGrainWindowCache<F> *windowCache) :sample(sample), pos(position), dur(duration), speed(speed)
{
buffer = sample->temp;
buffer = sample->temp.data();
// buffer = sample->temp;
sampleStartPos = sample->length * pos;
sampleDur = dur * (double)sample->mySampleRate;
sampleDurMinusOne = sampleDur - 1;
......@@ -183,7 +183,7 @@ public:
#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
//premake the grain using fast vector functions, and quadratic interpolation
double *sourceData = (double*)malloc(sampleDur * sizeof(double));
short* buffer = (short *)sample->temp;
short* buffer = (short *)sample->temp.data();
//convert sample to double data
vDSP_vflt16D(buffer + sampleStartPos, 1, sourceData, 1, min(sampleDur, sample->length - sampleStartPos));
//todo: wraping code
......@@ -258,6 +258,8 @@ public:
grainList grains;
maxiSample *sample;
// maxiGrainPlayer(){}
maxiGrainPlayer(maxiSample *sample) : sample(sample) {
}
......@@ -292,7 +294,12 @@ public:
double randomOffset;
double looper;
maxiTimestretch(){
position=0;
looper = 0;
// grainPlayer = new maxiGrainPlayer(sample);
randomOffset=0;
}
maxiTimestretch(maxiSample *sample) : sample(sample) {
position=0;
......@@ -304,7 +311,26 @@ public:
~maxiTimestretch() {
delete grainPlayer;
}
void setSample(maxiSample* sampleIn){
// could just erase the sample in player
// and replace?
if(grainPlayer){
delete grainPlayer;
grainPlayer = NULL;
}
sample = sampleIn;
grainPlayer = new maxiGrainPlayer(sample);
}
//
// void setSampleVec(vector<double> sampleIn){
// delete sample;
// sample = new maxiSample();
// sample->setSample(sampleIn);
//// sample = sampleIn;
// }
double getNormalisedPosition() {
return position / (double) sample->length;
}
......@@ -315,7 +341,7 @@ public:
void setPosition(double pos) {
position = pos * sample->length;
position = maxiMap::clamp(position, 0, sample->length-1);
position = maxiMap::clamp<double>(position, 0, sample->length-1);
}
......@@ -363,6 +389,13 @@ public:
maxiGrainWindowCache<F> windowCache;
double randomOffset;
maxiPitchShift(){
position=0;
cycles=0;
// grainPlayer = new maxiGrainPlayer(sample);
randomOffset=0;
}
maxiPitchShift(maxiSample *sample) : sample(sample) {
position=0;
cycles=0;
......@@ -374,6 +407,16 @@ public:
delete grainPlayer;
}
void setSample(maxiSample* sampleIn){
if(grainPlayer){
delete grainPlayer;
grainPlayer = NULL;
}
sample = sampleIn;
grainPlayer = new maxiGrainPlayer(sample);
}
double play(double speed, double grainLength, int overlaps, double posMod=0.0) {
position = position + 1;
cycles++;
......@@ -410,6 +453,16 @@ public:
long loopStart, loopEnd, loopLength;
double looper;
maxiPitchStretch(){
// grainPlayer = new maxiGrainPlayer(sample);
randomOffset=0;
loopStart = 0.0;
// loopEnd = sample->length;
// loopLength =sample->length;
position=0;
looper = 0;
}
maxiPitchStretch(maxiSample *sample) : sample(sample) {
grainPlayer = new maxiGrainPlayer(sample);
randomOffset=0;
......@@ -419,7 +472,20 @@ public:
position=0;
looper = 0;
}
void setSample(maxiSample* sampleIn){
if(grainPlayer){
delete grainPlayer;
grainPlayer = NULL;
}
sample = sampleIn;
grainPlayer = new maxiGrainPlayer(sample);
loopEnd = sample->length;
loopLength =sample->length;
}
double getNormalisedPosition() {
return position / (double) sample->length;
}
......@@ -430,7 +496,7 @@ public:
void setPosition(double pos) {
position = pos * sample->length;
position = maxiMap::clamp(position, 0, sample->length-1);
position = maxiMap::clamp<double>(position, 0, sample->length-1);
}
void setLoopStart(double val) {
......
/*
contains all bindings for use with emscripten
*/
#ifndef Maxi_Emscripten_maxiFFT_embind_h
#define Maxi_Emscripten_maxiFFT_embind_h
#include <emscripten.h>
#include <emscripten/bind.h>
//#include "fft.cpp"
using namespace emscripten;
EMSCRIPTEN_BINDINGS(my_module_maxiGrains) {
// -------------------------------------------------------------------------------------------
// LIBS
// MAXI TIMESTRETCH
class_<maxiTimestretch<hannWinFunctor> >("maxiTimestretch")
.smart_ptr_constructor("shared_ptr<maxiTimestretch<hannWinFunctor> >",&std::make_shared<maxiTimestretch<hannWinFunctor> >)
// .smart_ptr_constructor<maxiSample*>("shared_ptr<maxiTimestretch<hannWinFunctor> >",&std::make_shared<maxiTimestretch<hannWinFunctor> >)
.function("setSample", &maxiTimestretch<hannWinFunctor>::setSample, allow_raw_pointers())
.function("getNormalisedPosition", &maxiTimestretch<hannWinFunctor>::getNormalisedPosition)
.function("getPosition", &maxiTimestretch<hannWinFunctor>::getPosition)
.function("setPosition", &maxiTimestretch<hannWinFunctor>::setPosition)
.function("play", &maxiTimestretch<hannWinFunctor>::play)
.function("play2", &maxiTimestretch<hannWinFunctor>::play2)
;
// MAXI PITCHSHIFT
class_<maxiPitchShift<hannWinFunctor> >("maxiPitchShift")
.smart_ptr_constructor("shared_ptr<maxiPitchShift<hannWinFunctor> >",&std::make_shared<maxiPitchShift<hannWinFunctor> >)
.function("setSample", &maxiPitchShift<hannWinFunctor>::setSample, allow_raw_pointers())
.function("play", &maxiPitchShift<hannWinFunctor>::play)
;
// MAXI PITCHSTRETCH
class_<maxiPitchStretch<hannWinFunctor> >("maxiPitchStretch")
.smart_ptr_constructor("shared_ptr<maxiTimestretch<hannWinFunctor> >",&std::make_shared<maxiPitchStretch<hannWinFunctor> >)
// .smart_ptr_constructor<maxiSample*>("shared_ptr<maxiTimestretch<hannWinFunctor> >",&std::make_shared<maxiTimestretch<hannWinFunctor> >)
.function("setSample", &maxiPitchStretch<hannWinFunctor>::setSample, allow_raw_pointers())
.function("getNormalisedPosition", &maxiPitchStretch<hannWinFunctor>::getNormalisedPosition)
.function("getPosition", &maxiPitchStretch<hannWinFunctor>::getPosition)
.function("setPosition", &maxiPitchStretch<hannWinFunctor>::setPosition)
.function("setLoopStart", &maxiPitchStretch<hannWinFunctor>::setLoopStart)
.function("setLoopEnd", &maxiPitchStretch<hannWinFunctor>::setLoopEnd)
.function("play", &maxiPitchStretch<hannWinFunctor>::play)
;
};
#endif
......@@ -8,7 +8,7 @@
*/
#include "maxiMFCC.h"
#include "maxiMFCC_embind.h"
#ifdef __APPLE_CC__
template <>
......
......@@ -12,10 +12,12 @@
#pragma once
#pragma pack(16)
#include "maxiFFT.h"
//#include "../maxi_emscr_new.h"
//#include "maxiFFT.h"
#include <math.h>
#include <iostream>
#include <cstdlib>
#include <vector>
#ifdef __APPLE_CC__
#include <Accelerate/Accelerate.h>
#endif
......@@ -69,9 +71,10 @@ public:
calcMelFilterBank(sampleRate, numBins);
createDCTCoeffs();
}
void mfcc(float* powerSpectrum, T *mfccs) {
melFilterAndLogSquare(powerSpectrum);
dct(mfccs);
// void mfcc(float* powerSpectrum, T *mfccs) {
void mfcc(vector<float> powerSpectrum, vector<T> mfccs) {
melFilterAndLogSquare(powerSpectrum.data());
dct(mfccs.data());
}
private:
......
/*
contains all bindings for use with emscripten
*/
#ifndef Maxi_Emscripten_maxiMFCC_embind_h
#define Maxi_Emscripten_maxiMFCC_embind_h
#include <emscripten.h>
#include <emscripten/bind.h>
using namespace emscripten;
EMSCRIPTEN_BINDINGS(my_module_maxiMFCC) {
// -------------------------------------------------------------------------------------------
// LIBS
// MAXI MFCC
class_<maxiMFCC>("maxiMFCC")
// .constructor<>()
// .constructor<int>()
.smart_ptr_constructor("shared_ptr<maxiMFCC>",&std::make_shared<maxiMFCC>)
.function("setup", &maxiMFCC::setup)
.function("mfcc", &maxiMFCC::mfcc)
;
};
#endif
......@@ -40,6 +40,7 @@ using namespace emscripten;
EMSCRIPTEN_BINDINGS(my_module) {
register_vector<int>("VectorInt");
register_vector<double>("VectorDouble");
register_vector<char>("VectorChar");
// register_vector<float>("VectorFloat");
class_<vectorTools>("vectorTools")
......@@ -157,7 +158,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
// .constructor<>()
// .constructor<double, double>()
.smart_ptr_constructor("shared_ptr<maxiLagExp<double>>",&std::make_shared<maxiLagExp<double>>, allow_raw_pointers()) // not sure how to override constructors with smart_ptr
// .smart_ptr_constructor("shared_ptr<maxiLagExp<double>>",&std::make_shared<maxiLagExp<double>>)
// .smart_ptr_constructor("shared_ptr<maxiLagExp<double>>",&std::make_shared<maxiLagExp<double>>)
.function("init", &maxiLagExp<double>::init)
.function("addSample", &maxiLagExp<double>::addSample)
......@@ -171,7 +172,10 @@ EMSCRIPTEN_BINDINGS(my_module) {
.smart_ptr_constructor("shared_ptr<maxiSample>",&std::make_shared<maxiSample>)
// .property("length", &maxiSample::getLength, &maxiSample::setLength) // no work???
.function("getLength", &maxiSample::getLength)
.function("setSample", &maxiSample::setSample)
// .function("setSample", &maxiSample::setSample)
.function("setSample", select_overload<void(vector<double>&)>(&maxiSample::setSample))
.function("setSample", select_overload<void(vector<double>&, int)>(&maxiSample::setSample))
// .function("getSummary", &maxiSample::getSummary)
.function("isReady", &maxiSample::isReady)
......@@ -181,13 +185,14 @@ EMSCRIPTEN_BINDINGS(my_module) {
.function("play", select_overload<double()>(&maxiSample::play))
.function("play", select_overload<double(double)>(&maxiSample::play))
.function("play", select_overload<double(double, double, double)>(&maxiSample::play))
.function("play4", &maxiSample::play4)
.function("trigger", &maxiSample::trigger)
.function("clear", &maxiSample::clear)
// .function("normalise", &maxiSample::normalise)
// .function("autoTrim", &maxiSample::autoTrim)
// .function("load", &maxiSample::load)
// .function("read", &maxiSample::read, allow_raw_pointers())
;
......@@ -229,7 +234,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
.function("setSustain", &maxiEnv::setSustain)
.property("trigger", &maxiEnv::getTrigger, &maxiEnv::setTrigger)
;
// CONVERT
......@@ -332,6 +337,6 @@ EMSCRIPTEN_BINDINGS(my_module) {
.property("tick", &maxiClock::getTick, &maxiClock::setTick)
;
};
#endif
......@@ -532,7 +532,9 @@ std::vector<double>& maxiMix::ambisonic(double input,std::vector<double>&eight,d
eight[7]=input*sqrt((x*(1.0-y))*z);
return(eight);
}
// --------------------------------------------------------------------------------
// MAXI_SAMPLE
/*
//This is the maxiSample load function. It just calls read.
bool maxiSample::load(string fileName, int channel) {
myPath = fileName;
......@@ -568,7 +570,7 @@ bool maxiSample::loadOgg(string fileName, int channel) {
#endif
return 0;
}
*/
// -------------------------
// js bits
bool maxiSample::isReady(){
......@@ -579,10 +581,32 @@ bool maxiSample::isReady(){
}
void maxiSample::setSample(vector<double>& temp){
tempVec = temp;
// tempVec = temp;
length = temp.size();
for(int i = 0; i < length; i++){
this->temp.push_back(temp[i]*32767.0);
}
mySampleRate = 44100;
}
void maxiSample::setSample(vector<double>& temp, int sampleRate){
// tempVec = temp;
length = temp.size();
for(int i = 0; i < length; i++){
this->temp.push_back(temp[i]*32767.0);
}
mySampleRate = sampleRate;
}
//void maxiSample::setSampleChar(vector<char>& temp){
// this->temp = temp.data();
// length = temp.size();
//}
// -------------------------
//This sets the playback position to the start of a sample
......@@ -590,6 +614,89 @@ void maxiSample::trigger() {
position = 0;
recordPosition = 0;
}
/*
// attempt at using read with characters input from js
bool maxiSample::read(vector<char>& fileChars)
{
bool result;
ifstream inFile( myPath.c_str(), ios::in | ios::binary);
result = inFile.is_open();
if (result) {
bool datafound = false;
inFile.seekg(4, ios::beg);
inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize
inFile.seekg(16, ios::beg);
inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size
//inFile.seekg(20, ios::beg);
inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM
//inFile.seekg(22, ios::beg);
inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2)
//inFile.seekg(24, ios::beg);
inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate
//inFile.seekg(28, ios::beg);
inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate
//inFile.seekg(32, ios::beg);
inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign
//inFile.seekg(34, ios::beg);
inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample
//ignore any extra chunks
char chunkID[5]="";
chunkID[4] = 0;
int filePos = 20 + mySubChunk1Size;
while(!datafound && !inFile.eof()) {
inFile.seekg(filePos, ios::beg);
inFile.read((char*) &chunkID, sizeof(char) * 4);
inFile.seekg(filePos + 4, ios::beg);
inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data
filePos += 8;
if (strcmp(chunkID,"data") == 0) {
datafound = true;
}else{
filePos += myDataSize;
}
}
// read the data chunk
char * myData = (char*) malloc(myDataSize * sizeof(char));
inFile.seekg(filePos, ios::beg);
inFile.read(myData, myDataSize);
length=myDataSize*(0.5/myChannels);
inFile.close(); // close the input file
cout << "Ch: " << myChannels << ", len: " << length << endl;
if (myChannels>1) {
int position=0;
int channel=readChannel*2;
for (int i=channel;i<myDataSize+6;i+=(myChannels*2)) {
myData[position]=myData[i];
myData[position+1]=myData[i+1];
position+=2;
}
}
free(temp);
temp = (short*) malloc(myDataSize * sizeof(char));
memcpy(temp, myData, myDataSize * sizeof(char));
free(myData);
}else {
// cout << "ERROR: Could not load sample: " <<myPath << endl; //This line seems to be hated by windows
printf("ERROR: Could not load sample.");
}
return result; // this should probably be something more descriptive
}
//This is the main read function.
bool maxiSample::read()
......@@ -672,7 +779,252 @@ bool maxiSample::read()
return result; // this should probably be something more descriptive
}
*/
// -----------------
//This plays back at the correct speed. Always loops.
double maxiSample::play() {
position++;
if ((long) position >= length) position=0;
output = (double) temp[(long)position]/32767.0;
return output;
}
void maxiSample::setPosition(double newPos) {
position = maxiMap::clamp<double>(newPos, 0.0, 1.0) * length;
}
//start end and points are between 0 and 1
double maxiSample::playLoop(double start, double end) {