Paradigms useful for teaching Pd
This seems as likely a subcategory as any...
I'd like to connect with teachers using Pure Data in the classroom.
- Where are the stumbling blocks that you see students crash into frequently?
- (Anyone using Pd could chime in on that one... what are the things that confused you?)
- Are there any techniques/ideas/paradigms that helped the students to understand these difficulties more easily?
For a specific example: https://forum.pdpatchrepo.info/topic/13263/samphold-at-the-control-level -- "I want to get the number to update on the downbeat so it doesn't play anything while the number is being updated by some other process."
Extremely common scenario -- but I'll be danged if I can find anything in the help series that makes it clear.
This happens to be one of the sticking points for me -- which, lately, got me thinking about a paradigm of "feedforward" and "feedback" to cold inlets. It's (relatively) easy to understand chaining through hot inlets. Everything is immediate, and that's where the quoted question comes from -- if the only thing anyone taught you is how to chain immediate operations, then "save this datum for later" is scarcely even thinkable. (The quoted thread goes on to say "I'm having trouble explaining" -- meaning, whatever degree of exposure to Pd this user had, it wasn't enough to provide a vocabulary to talk about this problem.)
- "I have data now, but I don't want to use it until later" --> feed it forward to a storage object, then bang the storage object when you need it.
- "I want the next cycle of a loop to operate on the result of this cycle" --> feed it back to a storage object that's triggered by the loop.
This solves a bunch of problems. The quoted problem -- (data source) feeds forward to [f] right inlet. Or, initializing a counter at the beginning of the loop (feedforward). Or, building a list iteratively, but outputting only the final list (on each loop iteration, feed the list-in-progress forward to list storage, and bang the storage when the list is finished -- for this one in particular, I had struggled in the past with various bizarre usages of [spigot] but this is much easier).
One of the things I was missing over the last year and a half of getting up to speed in Pd is an established vocabulary of usage patterns. Sometimes I think Pd and Max pedagogy tries to stay away from typical computer-science problems -- but sooner or later, you're going to run into problems that have standard solutions. So why not collect them into a unified place? Like, in SC, for the fourth example below I can just write arrayOfMidiNotes.collect { |note| note.midicps }
and uses of collect
are all over the place in the help system... but in Pd, it took me literally over a year to figure out the best way to collect
/ map
. That's... kinda crazy.
hjh
Ofelia - using addons, GL_TEXTURE_3D and binding openGL functions
i think i learned how to integrate addons (not everything is working yet...).
this is what i added to ofxOfeliaPdBindings.h to integrate ofxVolumetrics:
class pdTexture3d
{
public:
pdTexture3d(){};
void allocate(int w, int h, int d, int internalGlDataType)
{
texture3d.allocate(w, h, d, internalGlDataType);
}
void loadData(unsigned char * data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(float* data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(unsigned short* data, int w, int h, int d, int xOffset, int yOffset, int zOffset, int glFormat)
{
texture3d.loadData(data, w, h, d, xOffset, yOffset, zOffset, glFormat);
}
void loadData(ofPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void loadData(ofShortPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void loadData(ofFloatPixels & pix, int d, int xOffset, int yOffset, int zOffset)
{
texture3d.loadData(pix, d, xOffset, yOffset, zOffset);
}
void bind()
{
texture3d.bind();
}
void unbind()
{
texture3d.unbind();
}
void clear()
{
texture3d.clear();
}
ofxTextureData3d getTextureData()
{
return texture3d.getTextureData();
}
private:
ofxTexture3d texture3d;
};
class pdVolumetrics
{
public:
pdVolumetrics(){};
void setup(int w, int h, int d, ofVec3f voxelSize, bool usePowerOfTwoTexSize=false)
{
volumetrics.setup(w, h, d, voxelSize, usePowerOfTwoTexSize);
}
void destroy()
{
volumetrics.destroy();
}
void updateVolumeData(unsigned char * data, int w, int h, int d, int xOffset, int yOffset, int zOffset)
{
volumetrics.updateVolumeData(data, w, h, d, xOffset, yOffset, zOffset);
}
void drawVolume(float x, float y, float z, float size, int zTexOffset)
{
volumetrics.drawVolume(x, y, z, size, zTexOffset);
}
void drawVolume(float x, float y, float z, float w, float h, float d, int zTexOffset)
{
volumetrics.drawVolume(x, y, z, w, h, d, zTexOffset);
}
bool isInitialized()
{
return volumetrics.isInitialized();
}
int getVolumeWidth()
{
return volumetrics.getVolumeWidth();
}
int getVolumeHeight()
{
return volumetrics.getVolumeHeight();
}
int getVolumeDepth()
{
return volumetrics.getVolumeDepth();
}
ofFbo & getFboReference()
{
return volumetrics.getFboReference();
}
int getRenderWidth()
{
return volumetrics.getRenderWidth();
}
int getRenderHeight()
{
return volumetrics.getRenderHeight();
}
float getXyQuality()
{
return volumetrics.getXyQuality();
}
float getZQuality()
{
return volumetrics.getZQuality();
}
float getThreshold()
{
return volumetrics.getThreshold();
}
float getDensity()
{
return volumetrics.getDensity();
}
void setXyQuality(float q)
{
volumetrics.setXyQuality(q);
}
void setZQuality(float q)
{
volumetrics.setZQuality(q);
}
void setThreshold(float t)
{
volumetrics.setThreshold(t);
}
void setDensity(float d)
{
volumetrics.setDensity(d);
}
void setRenderSettings(float xyQuality, float zQuality, float dens, float thresh)
{
volumetrics.setRenderSettings(xyQuality, zQuality, dens, thresh);
}
void setVolumeTextureFilterMode(GLint filterMode)
{
volumetrics.setVolumeTextureFilterMode(filterMode);
}
private:
ofxVolumetrics volumetrics;
};
class pdImageSequencePlayer
{
public:
pdImageSequencePlayer(){};
void init(std::string prefix, int digits, std::string extension, int start)
{
imageSequencePlayer.init(prefix, digits, extension, start);
}
int getWidth()
{
return imageSequencePlayer.getWidth();
}
int getHeight()
{
return imageSequencePlayer.getHeight();
}
ofPixels_<unsigned char> getPixels()
{
return imageSequencePlayer.getPixels();
}
int getSequenceLength()
{
return imageSequencePlayer.getSequenceLength();
}
bool loadNextFrame()
{
return imageSequencePlayer.loadNextFrame();
}
bool loadPreviousFrame()
{
return imageSequencePlayer.loadPreviousFrame();
}
bool loadFrame(int n)
{
return imageSequencePlayer.loadFrame(n);
}
int getCurrentFrameNumber()
{
return imageSequencePlayer.getCurrentFrameNumber();
}
void setCurrentFrameNumber(int i)
{
imageSequencePlayer.setCurrentFrameNumber(i);
}
bool isInitialized()
{
return imageSequencePlayer.isInitialized();
}
private:
ofxImageSequencePlayer imageSequencePlayer;
};
CPU usage of idle patches, tabread4~?
@zigmhount said:
Good advice on the discontinuities. I was kind of hoping that [phasor~] would handle this better than restarting [line~] from 1 to 0, but I suppose that it also just jump from 1 to 0?
Yep. Regardless of whether you're using [line~] or [phasor~] to drive [tabread4~], discontinuities can happen anytime you abruptly jump from one spot to another. This isn't unique to Pd, if you perform edits to a waveform in any DAW without crossfades at the edit points, you will get clicks/pops (unless you get lucky & happen to edit at a zero crossing). So, if the first & last values stored in your array (loop) are not the same & the loop restarts (either beginning a new 0->1 ramp with [line~] or letting [phasor~] wrap around), you'll get a pop unless you use windowing.
In your example, you record the ramp up and ramp down into the array itself, right? Is that not audible when looping the same array over and over? Thanks to this ramp in the array, I guess that [tabread4~] may not click even if started without a volume ramp in, would it?
Yes indeed, that example essentially records the fade in/out into the array, so you wouldn't hear clicks when the loop wraps even without using a window with [tabread4~]. However, note that this is only one of the causes I mentioned... if you're eventually planning to add any playback controls with abrupt changes (such as pause/stop, start from the middle, rewind, jump to a new position, etc), you'll need a fade out before the change and a fade in after the change. FYI, my personal use for recording the fade into the array itself is because I sometimes use a phase vocoder for time stretching of my loops, which seems to misbehave if I have extreme values at the start/end of the array.
And, yes, the windowing can be audible, but it really depends on the nature of the audio that you're recording into the array. I randomly chose a 10ms fade in/out for the example above, but that could be any duration you like (you might want it to be adjustable if you're looping many different types of sounds, to experiment with shorter/longer fade times). There are also ways of shaping the curve of the fades if you really want to minimize their chances of being audible. But even if the fades are obvious, I think you'll still find them to be a million times less strident than a loud speaker pop.
RMS vs FFT complex magnitudes
I'm up to the beginning of Katja V's Fourier Transform section and I've already found a few answers to my questions. I also managed to get the sum of FFT term amplitudes to match the RMS value for arbitrary input. Here's the patch:
Inside [pd computerMagnitudes]:
compareTimeFreqAmpl2.pd
All the things on the left are just tools to fill the input table, but you can also just draw. Once you have your signal, bang computeMagnitudes to measure its amplitude both ways.
I made a couple of simplifications that not only got the test working but also gave me more confidence that I was comparing apples to apples:
- I'm computing RMS and the FFT from a single static 1024 vector, so I'm now comparing two views of the exact same signal and there's no need for averaging.
- I learned from Katja that if you perform a complex FFT on a real signal, you don't have to worry about which terms to double because the FFT gives you those terms's double in the upper half of the output explicitly. The real FFT skips the upper half for efficiency because it's related to the lower half.
- I also learned that even the cosine and sine components of each harmonic are uncorrelated signals, so I now sum their magnitudes individually across all harmonics. There's no need to compute the magnitude of each FFT term first.
So I think the issue I was having with noise was just an artifact of a badly programmed test, probably having to do with the way I was averaging term magnitudes, but I don't really know.
7/18/2020 update: I've found info in Katja's blog that suggests that this patch is wrong (or maybe even not possible). Exhibit A:
IMHO, this contradicts what she spent so much effort establishing on the prior two pages (http://www.katjaas.nl/sinusoids2/sinusoids2.html
http://www.katjaas.nl/correlation/correlation.html), that the cos and sine components of all FFT terms are orthogonal. If they're orthogonal, how could they cancel each other out?
She raises a another point on the FFT output page that really makes me wonder why my patch seems to work:
In this case I agree--Fourier coefficents are really the peak amplitudes of the cos and sine components--but my confusion over this is what made me program the patch the way that I did. So why is it working?
sending / receiving variables with emscripten ofelia?
i managed to send and receive values (numbers) with EM_ASM between java script and c++
here is an example: http://emasm.handmadeproductions.de/
EMASM.zip
but it works only with regular open frameworks programs yet, not with ofelia...
#include "ofApp.h"
#include "emscripten.h"
//--------------------------------------------------------------
void ofApp::setup(){
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
EM_ASM_({
console.log('I send: ' + $0);
document.getElementById("display_time").textContent = Number($0).toFixed(2);
}, ofGetElapsedTimef());
int size = EM_ASM_INT({
console.log('I received size: ' + document.getElementById("slider_size").value);
return document.getElementById("slider_size").value;
});
int blue = EM_ASM_INT({
console.log('I received blue: ' + document.getElementById("slider_blue").value);
return document.getElementById("slider_blue").value;
});
int t = ofGetElapsedTimef();
ofSetColor(t % 255, t % 255, blue);
ofRectangle rect;
rect.x = 10;
rect.y = 10;
rect.width = size * 1.344827586;
rect.height = size;
ofDrawRectangle(rect);
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}
@Cuinjune i wonder if it is possible to access ofelia variables from ofApp.cpp,
or if it could be possible to use EM_ASM in an future update inside an ofelia script?
Or is it possible to already use EM_ASM inside an ofelia script and I just need to know how to use it with Lua?
PD's scheduler, timing, control-rate, audio-rate, block-size, (sub)sample accuracy,
@EEight said:
@lacuna said:
I just see this flag on linux:
-nosleep -- spin, don't sleep (may lower latency on multi-CPUs)
Oh yes and there are startup flags for loading a different scheduler (I corrected this in my first post now)
https://puredata.info/docs/faq/commandline
-rt or -realtime -- use real-time priority
-nrt -- don't use real-time priority
-sleep -- sleep when idle, don't spin (true by default)
-nosleep -- spin, don't sleep (may lower latency on multi-CPUs)
-schedlib <file> -- plug in external scheduler
-extraflags <s> -- string argument to send schedlib
-batch -- run off-line as a batch process
-nobatch -- run interactively (true by default)
Not sure, would be interested to know too.
@EEight output of full text search of sleep with grep in pd's source folder -nri flags set:
https://pastebin.com/3mBw6Mnj
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/u_pdsend.c:86: sleep (nretry < 5 ? 1 : 5);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_stuff.h:65:extern int sys_sleepgrain;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_stuff.h:163:EXTERN void sys_microsleep(int microsec);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_stuff.h:369:EXTERN int* get_sys_sleepgrain(void);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:58:int sys_nosleep = 0; /* skip all "sleep" calls and spin instead */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:115:int* get_sys_sleepgrain() { return &sys_sleepgrain; }
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:424:"-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:520:"-sleep -- sleep when idle, don't spin (true by default)\n",
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:521:"-nosleep -- spin, don't sleep (may lower latency on multi-CPUs)\n",
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:732: else if (!strcmp(*argv, "-sleepgrain"))
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:737: sys_sleepgrain = 1000 * atof(argv[1]);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:1242: else if (!strcmp(*argv, "-sleep"))
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:1244: sys_nosleep = 0;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:1247: else if (!strcmp(*argv, "-nosleep"))
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_main.c:1249: sys_nosleep = 1;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:202:extern int sys_nosleep;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:204:/* sleep (but cancel the sleeping if pollem is set and any file descriptors are
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:207:sleep. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:208:static int sys_domicrosleep(int microsec, int pollem)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:226: perror("microsleep select");
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:242: Sleep(microsec/1000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:244: usleep(microsec);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:251: /* sleep (but if any incoming or to-gui sending to do, do that instead.)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:253:void sys_microsleep(int microsec)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:256: sys_domicrosleep(microsec, 1);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_inter.c:909: int didsomething = sys_domicrosleep(0, 1);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:16: correct thread synchronization (by defining THREADSIGNAL) or just sleeping
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:21: switch to usleep in s_inter.c
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:91:#include <windows.h> /* for Sleep() */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:549: sys_microsleep(sys_sleepgrain);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:550: if (!pa_stream) /* sys_microsleep() may have closed device */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:591: sys_microsleep(sys_sleepgrain);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_pa.c:592: if (!pa_stream) /* sys_microsleep() may have closed device */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_oss.c:672: sys_microsleep(2000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:105:/* if more than this sleep detected, should be more than periodsize/samplerate ??? */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:106:static double sleep_time;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:340: sleep_time = (float) alsamm_period_size/ (float) alsamm_sr;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:798: sleep(1); /* wait until the suspend flag is released */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:1336: if ((timenow = sys_getrealtime()) > (timelast + sleep_time))
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsamm.c:1342: timenow,timelast,sleep_time,(timelast + sleep_time));
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/s_audio_alsa.c:691: sys_microsleep(5000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:23:int sys_usecsincelastsleep(void);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:24:int sys_sleepgrain;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:442:will now sleep. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:454: if (sys_sleepgrain < 100)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:455: sys_sleepgrain = sys_schedadvance/4;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:456: if (sys_sleepgrain < 100)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:457: sys_sleepgrain = 100;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:458: else if (sys_sleepgrain > 5000)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:459: sys_sleepgrain = 5000;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:477: the machine sleeps. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:539: /* if even that had nothing to do, sleep. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:541: sys_microsleep(sys_sleepgrain);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:574: Sleep(1000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/src/m_sched.c:576: sleep(1);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptwinmm.c:67:PMEXPORT void Pt_Sleep(int32_t duration)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptwinmm.c:69: Sleep(duration);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptmacosx_mach.c:128:void Pt_Sleep(int32_t duration)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptmacosx_mach.c:130: usleep(duration * 1000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptmacosx_cf.c:137:void Pt_Sleep(int32_t duration)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptmacosx_cf.c:139: usleep(duration * 1000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptlinux.c:14:of sleeping when realtime threads request a sleep of <=2ms (as a way
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptlinux.c:132:void Pt_Sleep(int32_t duration)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/ptlinux.c:134: usleep(duration * 1000);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/porttime.h:82: Pt_Sleep() pauses, allowing other threads to run.
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/porttime/porttime.h:88:PMEXPORT void Pt_Sleep(int32_t duration);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/portmidi/pm_mac/pmmacosxcm.c:492: usleep((useconds_t)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portmidi/patches/mac_limit_rate_override.patch:52: usleep((useconds_t)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/win/pa_win_util.c:102:void Pa_Sleep( long msec )
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/win/pa_win_util.c:104: Sleep( msec );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:108:void Pa_Sleep( long msec )
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:110:#ifdef HAVE_NANOSLEEP
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:116: nanosleep(&req, &rem);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:117: /* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:120: { /* to usleep must be < 1000000. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:121: usleep( 999000 );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:124: usleep( msec * 1000 );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:599: /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:601: Pa_Sleep( intervalMsec );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:644: PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:645: Pa_Sleep( th->throttledSleepTime );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/os/unix/pa_unix_util.c:704: Pa_Sleep( intervalMsec );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/wmme/pa_win_wmme.c:2185: unsigned long throttledSleepMsecs;
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/wmme/pa_win_wmme.c:2565: /* time to sleep when throttling due to >100% cpu usage.
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/wmme/pa_win_wmme.c:2567: stream->throttledSleepMsecs =
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/wmme/pa_win_wmme.c:3194: /* sleep to give other processes a go */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/wmme/pa_win_wmme.c:3195: Sleep( stream->throttledSleepMsecs );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c:395: /* No match yet, so let's sleep and try again. */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c:396: Pa_Sleep( 100 );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h:69:#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c:454: Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c:535: Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c:607: Pa_Sleep( msecPerBuffer );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/coreaudio/pa_mac_core.c:2722: Pa_Sleep( 100 );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/asio/pa_asio.cpp:3401: Sleep(1);
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/alsa/pa_linux_alsa.c:1129: Pa_Sleep( 10 );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/alsa/pa_linux_alsa.c:2759: /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/alsa/pa_linux_alsa.c:3831: Pa_Sleep( 1 ); /* avoid hot loop */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/alsa/pa_linux_alsa.c:3849: if( timeouts > 1 ) /* sometimes device times out, but normally once, so we do not sleep any time */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/hostapi/alsa/pa_linux_alsa.c:3851: Pa_Sleep( 1 ); /* avoid hot loop */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/src/common/pa_util.h:152:/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/include/portaudio.h:1211:/** Put the caller to sleep for at least 'msec' milliseconds. This function is
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/include/portaudio.h:1215: The function may sleep longer than requested so don't rely on this for accurate
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/include/portaudio.h:1218:void Pa_Sleep( long msec );
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/include/pa_win_wmme.h:64: to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100%
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/portaudio/portaudio/include/pa_linux_alsa.h:91:/** Set the maximum number of times to retry opening busy device (sleeping for a
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x5.htm:599:<P> In linux, a "-nosleep" flag causes Pd to poll instead of sleeping as it
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x5.htm:798:<P> Fixed a thread-safety problem in sys_microsleep().
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x5.htm:1224:the controlling parameter for MIDI jitter is "-sleepgrain", which specifies
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x5.htm:1225:the interval of time Pd sleeps when it believes it's idle.
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x5.htm:1373:<P> -sleepgrain: if you aren't using audio I/O, this can reduce time jitter in
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:488:scheduling; "-sleepgrain 1" sets the sleep grain to 1 (see under MIDI below),
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:489:and typing "-rt -sleepgrain 1" does both.
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:527:-sleepgrain <n> -- specify number of milliseconds to sleep when idle
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:573:-nosleep -- never relinquish CPU (only for multiprocessors!)
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:610:<H4> MIDI and sleepgrain</H4>
/pd-0.50-2.src.tar.gz.extracted/pd-0.50-2/doc/1.manual/x3.htm:619:<P> The "sleepgrain" controls how long (in milliseconds) Pd sleeps between
good night sweet dreams
Audiolab is now available on deken!
my "audiolab" abstraction library is now available on deken. You'll need Pd-0.50 or later to run this.
Please report any bugs on github: https://github.com/solipd/AudioLab
here is a picture to draw you in (:
Edit:
list of objects:
Soundfle processing
pp.sfplayer~ ... variable-speed soundfile player
pp.grainer~ ... granular sampler
pp.fft-stretch~ ... pvoc time stretching & pitch shifting
Spatialization
pp.pan~ ... constant power stereo panning
pp.midside~ ... mid-side panning
pp. spat8~ ... 8-channel distance based amplitude panning
pp.doppler~ ... doppler effect, damping & amplitude modulation
pp.dopplerxy~ ... xy doppler effect
Effects
pp.freqshift~ ... ssb frequency shifter
pp.pitchshift~ ... pitch shifter
pp.eqfilter~ ... eq-filter (lowpass, highpass, resonant, bandpass, notch, peaking, lowshelf, highshelf or allpass)
pp.vcfilter~ ... signal controlled filter (lowpass, highpass, resonant)
pp.clop~ ... experimental comb-lop-filter
pp.ladder~ ... moogish filter
pp.dynamics~ ... compressor / expander
pp.env~ ... simple envelope follower
pp.graindelay~ ... granular delay
pp.rev~ ... fdn-reverberator based on rev3~
pp.twisted-delays~ ... multipurpose twisted delay-thing
pp.shepphaser~ ... shepard tone-like phaser effect
pp.echo~ ... "analog" delay
Spectral processing
pp.fft-block~ ... audio block delay
pp.fft-split~ ... spectral splitter
pp.fft-gate~ ... spectral gate
pp.fft-pitchshift~ ... pvoc based pitchshifter
pp.fft-timbre~ ... spectral bin-reordering
pp.fft-partconv~ ... partitioned low latency convolution
pp.fft-freeze~ ... spectral freezer
Misc.
pp.in~ .... mic. input
pp.out~ ... stereo output & soundfile recorder
pp.out-8~ ... 8 channel output & soundfile recorder
pp.sdel~ ... samplewise delay
pp.lfnoise~ ... low frequency noise generator
pp.spectrum~ ... spectrum analyser
pp.xycurve
Easy resonant lp filter?
Fair enough about passband attenuation -- sure, it's legit for a filter either to boost the resonance or to attenuate elsewhere.
in all likelihood it's an emulation of the lowpass species.
Rant time.
See, but this gets to my broader point: Why do you have to guess what kind of filter it is?
Why does the help patch not simply say explicitly that it's a lowpass filter?
This shouldn't even be a conversation. Just add one word to the help patch, and then the help answers rather than raises questions.
Same problem with [vcf~]'s help patch (re: "probably the right outlet of vcf~"):
Outlets:
0 signal: - the filtered signal (real part).
1 signal: - the filtered signal (imaginary part).
Now let's suppose you're a digital media artist with some degree of technical sophistication, but not quite enough mathematics to understand Julius Smith's digital filters book.
How, actually, is one supposed to guess, based on the information in the help patch, that real = bandpass and imaginary = lowpass? Oh right. I'm gonna spend a couple of months to grok Hilbert transforms until it finally dawns on me. Now that is user-friendly documentation.
If in fact it really is the right outlet of vcf~ (and it appears to be), then I shouldn't have to open the thread on the forum at all. I should be able to find the answer in the help. (I did look at the help patch before asking, but plainly the help is not written for PD's actual user base.)
FWIW I have a similar complaint with SuperCollider's documentation -- quite often, details are either missing or stated in terms that are not plainly relevant to the user's most likely question.
hjh
new vanilla list sort
@ingox If you are looking for source code for any old extended externals they are all in https://sourceforge.net/projects/pure-data/files/pd-extended/0.43.4/Pd-extended_0.43.4-source.tar.bz2/download
Worth grabbing a copy while it remains available.
All the "makefile"s are included.
Useful for compiling externals for 64-bit (when they work).
I have seen the sort message almost hidden in a subpatch in 12-tut.pd in a tutorial on scalars here...... https://puredata.info/community/projects/convention04/lectures/tk-barknecht/tut.tgz
and it is mentioned (again... sort of.... with no explanation of the message call) as a function in Chapter 2.9.1 here...... http://puredata.info/docs/manuals/pd/x2.htm
and so it is also in Pd's \doc\1.manual\x2.htm
Zexy sort below. But it looks like the canvas sort is in g.graph.c.
There is an "if scalar sort" statement in there.
However g.graph.c has been disappeared from 0.49...... so......?
David.
.... sort.c.... (zexy)
In/*
* sort : sort a list of floats
*
* (c) 1999-2011 IOhannes m zmölnig, forum::für::umläute, institute of electronic music and acoustics (iem)
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "zexy.h"
/* ------------------------- sort ------------------------------- */
/*
SHELL SORT: simple and easy
*/
static t_class *sort_class;
typedef struct _sort
{
t_object x_obj;
int bufsize;
t_float *buffer;
t_int *indices;
int ascending;
t_outlet*indexOut, *sortedOut;
} t_sort;
static void sort_dir(t_sort *x, t_float f)
{
x->ascending = (f < 0.f)?0:1;
}
static void sort_buffer(t_sort *x, int argc, t_atom *argv)
{
int n = argc;
t_float *buf;
t_atom *atombuf = argv;
if (argc != x->bufsize) {
if (x->buffer) freebytes(x->buffer, x->bufsize * sizeof(t_float));
if (x->indices)freebytes(x->indices, x->bufsize * sizeof(t_int));
x->bufsize = argc;
x->buffer = getbytes(x->bufsize * sizeof(t_float));
x->indices = getbytes(x->bufsize * sizeof(t_int));
}
buf = x->buffer;
while (n--){
*buf++ = atom_getfloat(atombuf++);
x->indices[n] = n;
}
}
static void sort_list(t_sort *x, t_symbol *s, int argc, t_atom *argv)
{
int step = argc, n;
t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom) * argc);
t_float *buf;
t_int *idx;
int i, loops = 1;
sort_buffer(x, argc, argv);
buf = x->buffer;
idx = x->indices;
while (step > 1) {
step = (step % 2)?(step+1)/2:step/2;
i = loops;
loops += 2;
while(i--) { /* there might be some optimization in here */
for (n=0; n<(argc-step); n++) {
if (buf[n] > buf[n+step]) {
t_int i_tmp = idx[n];
t_float f_tmp = buf[n];
buf[n] = buf[n+step];
buf[n+step] = f_tmp;
idx[n] = idx[n+step];
idx[n+step] = i_tmp;
}
}
}
}
if (x->ascending)
for (n = 0; n < argc; n++) SETFLOAT(&atombuf[n], idx[n]);
else
for (n = 0, i=argc-1; n < argc; n++, i--) SETFLOAT(&atombuf[n], idx[i]);
outlet_list(x->indexOut , gensym("list"), n, atombuf);
if (x->ascending)
for (n = 0; n < argc; n++) SETFLOAT(&atombuf[n], buf[n]);
else
for (n = 0, i=argc-1; n < argc; n++, i--) SETFLOAT(&atombuf[n], buf[i]);
outlet_list(x->sortedOut, gensym("list"), n, atombuf);
freebytes(atombuf, argc*sizeof(t_atom));
}
static void *sort_new(t_floatarg f)
{
t_sort *x = (t_sort *)pd_new(sort_class);
x->ascending = (f < 0.f)?0:1;
x->sortedOut=outlet_new(&x->x_obj, gensym("list"));
x->indexOut=outlet_new(&x->x_obj, gensym("list"));
x->bufsize = 0;
x->buffer = NULL;
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("direction"));
return (x);
}
static void sort_help(t_sort*x)
{
post("\n%c sort\t\t:: sort a list of numbers", HEARTSYMBOL);
}
void sort_setup(void)
{
sort_class = class_new(gensym("sort"), (t_newmethod)sort_new,
0, sizeof(t_sort), 0, A_DEFFLOAT, 0);
class_addlist (sort_class, sort_list);
class_addmethod (sort_class, (t_method)sort_dir, gensym("direction"), A_DEFFLOAT, 0);
class_addmethod(sort_class, (t_method)sort_help, gensym("help"), A_NULL);
zexy_register("sort");
}
`
[small job offer] porting max external to pd
Edit 1: Took a shot porting it in this little textarea. Probably doesn't compile yet...
Edit 2: Ok, this should compile now. I haven't actually tried to instantiate it yet, though. It's possible I set it up with the wrong number of xlets.
Edit 3: Seems to instantiate ok. It appears it doesn't take signal input so the CLASS_MAINSIGNALIN macro is neccessary. Just comment that part out to make it a control signal.
Note-- in my port it's called [vb_fourses~]
for the reason noted below.
I have no idea if the algorithm behaves correctly, but it does output sound.
Btw-- AFAICT you should be able to compile this external for the 64-bit version of Purr Data and it should work properly. It doesn't require a special 64-bit codepath in Pd so I commented that part out.
Btw 2-- there should probably be a "best practices" rule that states you can only name your class something that is a legal C function name. Because this class doesn't follow that practice I made a mistake in the port. Further, the user will make a mistake because I had to change the class name. If I had instead made the setup function a different name than the creator I would create an additional problem that would force users to declare the lib before using it. Bad all around, and not worth whatever benefit there is to naming a class "foo.bar" instead of "foo_bar"
/*
#include "ext.h"
#include "ext_obex.h"
#include "z_dsp.h"
#include "ext_common.h"
*/
#include "m_pd.h"
#include "math.h"
/*
a chaotic oscillator network
based on descriptions of the 'fourses system' by ciat-lonbarde
www.ciat-lonbarde.net
07.april 2013, volker b?hm
*/
#define NUMFOURSES 4
static void *myObj_class;
typedef struct {
// this is a horse... basically a ramp generator
double val;
double inc;
double dec;
double adder;
double incy, incym1; // used for smoothing
double decy, decym1; // used for smoothing
} t_horse;
typedef struct {
t_object x_obj;
double r_sr;
t_horse fourses[NUMFOURSES+2]; // four horses make a fourse...
double smoother;
t_sample x_f;
} t_myObj;
// absolute limits
static void myObj_hilim(t_myObj *x, t_floatarg input);
static void myObj_lolim(t_myObj *x, t_floatarg input);
// up and down freqs for all oscillators
static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4);
static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4);
static void myObj_smooth(t_myObj *x, t_floatarg input);
static void myObj_info(t_myObj *x);
// DSP methods
static void myObj_dsp(t_myObj *x, t_signal **sp);
static t_int *myObj_perform(t_int *w);
//void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate,
// long maxvectorsize, long flags);
//void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins,
// double **outs, long numouts, long sampleframes, long flags, void *userparam);
//
static void *myObj_new( t_symbol *s, int argc, t_atom *argv);
//void myObj_assist(t_myObj *x, void *b, long m, long a, char *s);
void vb_fourses_tilde_setup(void) {
t_class *c;
myObj_class = class_new(gensym("vb_fourses~"), (t_newmethod)myObj_new, 0, sizeof(t_myObj),
0, A_GIMME, NULL);
c = myObj_class;
class_addmethod(c, (t_method)myObj_dsp, gensym("dsp"), A_CANT, 0);
// class_addmethod(c, (t_method)myObj_dsp64, gensym("dsp64"), A_CANT, 0);
class_addmethod(c, (t_method)myObj_smooth, gensym("smooth"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_hilim, gensym("hilim"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_lolim, gensym("lolim"), A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_upfreq, gensym("upfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_downfreq, gensym("downfreq"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(c, (t_method)myObj_info, gensym("info"), 0);
//class_addmethod(c, (t_method)myObj_assist, "assist", A_CANT,0);
CLASS_MAINSIGNALIN(myObj_class, t_myObj, x_f);
// class_dspinit(c);
// class_register(CLASS_BOX, c);
post("vb_fourses~ by volker b?hm\n");
// return 0;
}
static void myObj_smooth(t_myObj *x, t_floatarg input) {
// input = CLAMP(input, 0., 1.);
if (input < 0.) input = 0;
if (input > 1.) input = 1;
x->smoother = 0.01 - pow(input,0.2)*0.01;
}
static void myObj_hilim(t_myObj *x, t_floatarg input) {
x->fourses[0].val = input; // store global high limit in fourses[0]
}
static void myObj_lolim(t_myObj *x, t_floatarg input) {
x->fourses[5].val = input; // store global low limit in fourses[5]
}
static void myObj_upfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) {
x->fourses[1].inc = fabs(freq1)*4*x->r_sr;
x->fourses[2].inc = fabs(freq2)*4*x->r_sr;
x->fourses[3].inc = fabs(freq3)*4*x->r_sr;
x->fourses[4].inc = fabs(freq4)*4*x->r_sr;
}
static void myObj_downfreq(t_myObj *x, t_floatarg freq1, t_floatarg freq2, t_floatarg freq3, t_floatarg freq4) {
x->fourses[1].dec = fabs(freq1)*-4*x->r_sr;
x->fourses[2].dec = fabs(freq2)*-4*x->r_sr;
x->fourses[3].dec = fabs(freq3)*-4*x->r_sr;
x->fourses[4].dec = fabs(freq4)*-4*x->r_sr;
}
//#pragma mark 64bit dsp-loop ------------------
//void myObj_dsp64(t_myObj *x, t_object *dsp64, short *count, double samplerate,
// long maxvectorsize, long flags) {
// object_method(dsp64, gensym("dsp_add64"), x, myObj_perform64, 0, NULL);
//
// if(samplerate<=0) x->r_sr = 1.0/44100.0;
// else x->r_sr = 1.0/samplerate;
//
//
//}
//static void myObj_perform64(t_myObj *x, t_object *dsp64, double **ins, long numins,
// double **outs, long numouts, long sampleframes, long flags, void *userparam){
//
// t_double **output = outs;
// int vs = sampleframes;
// t_horse *fourses = x->fourses;
// double val, c, hilim, lolim;
// int i, n;
//
// if (x->x_obj.z_disabled)
// return;
//
// c = x->smoother;
// hilim = fourses[0].val;
// lolim = fourses[5].val;
//
// for(i=0; i<vs; i++)
// {
// for(n=1; n<=NUMFOURSES; n++) {
// // smoother
// fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c);
// fourses[n].incym1 = fourses[n].incy;
//
// fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c);
// fourses[n].decym1 = fourses[n].decy;
//
// val = fourses[n].val;
// val += fourses[n].adder;
//
// if(val <= fourses[n+1].val || val <= lolim ) {
// fourses[n].adder = fourses[n].incy;
// }
// else if( val >= fourses[n-1].val || val >= hilim ) {
// fourses[n].adder = fourses[n].decy;
// }
//
// output[n-1][i] = val;
//
// fourses[n].val = val;
// }
// }
//
// return;
//
//}
//#pragma mark 32bit dsp-loop ------------------
static void myObj_dsp(t_myObj *x, t_signal **sp)
{
dsp_add(myObj_perform, 6, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n);
if(sp[0]->s_sr<=0)
x->r_sr = 1.0/44100.0;
else x->r_sr = 1.0/sp[0]->s_sr;
}
static t_int *myObj_perform(t_int *w)
{
t_myObj *x = (t_myObj*)(w[1]);
t_float *out1 = (float *)(w[2]);
t_float *out2 = (float *)(w[3]);
t_float *out3 = (float *)(w[4]);
t_float *out4 = (float *)(w[5]);
int vs = (int)(w[6]);
// Hm... not sure about this member. I don't think we can disable individual
// objects in Pd...
// if (x->x_obj.z_disabled)
// goto out;
t_horse *fourses = x->fourses;
double val, c, hilim, lolim;
int i, n;
c = x->smoother;
hilim = fourses[0].val;
lolim = fourses[5].val;
for(i=0; i<vs; i++)
{
for(n=1; n<=NUMFOURSES; n++) {
// smoother
fourses[n].incy = fourses[n].inc*c + fourses[n].incym1*(1-c);
fourses[n].incym1 = fourses[n].incy;
fourses[n].decy = fourses[n].dec*c + fourses[n].decym1*(1-c);
fourses[n].decym1 = fourses[n].decy;
val = fourses[n].val;
val += fourses[n].adder;
if(val <= fourses[n+1].val || val <= lolim ) {
fourses[n].adder = fourses[n].incy;
}
else if( val >= fourses[n-1].val || val >= hilim ) {
fourses[n].adder = fourses[n].decy;
}
fourses[n].val = val;
}
out1[i] = fourses[1].val;
out2[i] = fourses[2].val;
out3[i] = fourses[3].val;
out4[i] = fourses[4].val;
}
//out:
return w+7;
}
static void myObj_info(t_myObj *x) {
int i;
// only fourses 1 to 4 are used
post("----- fourses.info -------");
for(i=1; i<=NUMFOURSES; i++) {
post("fourses[%ld].val = %f", i, x->fourses[i].val);
post("fourses[%ld].inc = %f", i, x->fourses[i].inc);
post("fourses[%ld].dec = %f", i, x->fourses[i].dec);
post("fourses[%ld].adder = %f", i, x->fourses[i].adder);
}
post("------ end -------");
}
void *myObj_new(t_symbol *s, int argc, t_atom *argv)
{
t_myObj *x = (t_myObj *)pd_new(myObj_class);
// dsp_setup((t_pxobject*)x, 0);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
outlet_new((t_object *)x, &s_signal);
x->r_sr = 1.0/sys_getsr();
if(sys_getsr() <= 0)
x->r_sr = 1.0/44100.f;
int i;
for(i=1; i<=NUMFOURSES; i++) {
x->fourses[i].val = 0.;
x->fourses[i].inc = 0.01;
x->fourses[i].dec = -0.01;
x->fourses[i].adder = x->fourses[i].inc;
}
x->fourses[0].val = 1.; // dummy 'horse' only used as high limit for fourses[1]
x->fourses[5].val = -1.; // dummy 'horse' only used as low limit for fourses[4]
x->smoother = 0.01;
return x;
}
//void myObj_assist(t_myObj *x, void *b, long m, long a, char *s) {
// if (m==1) {
// switch(a) {
// case 0: sprintf (s,"message inlet"); break;
// }
// }
// else {
// switch(a) {
// case 0: sprintf (s,"(signal) signal out osc1"); break;
// case 1: sprintf(s, "(signal) signal out osc2"); break;
// case 2: sprintf(s, "(signal) signal out osc3"); break;
// case 3: sprintf(s, "(signal) signal out osc4"); break;
// }
//
// }
//}