1
/* Automatically generated from Squeak on #(19 March 2005 10:09:04 am) */
9
/* Default EXPORT macro that does nothing (see comment in sq.h): */
10
#define EXPORT(returnType) returnType
12
/* Do not include the entire sq.h file but just those parts needed. */
13
/* The virtual machine proxy definition */
14
#include "sqVirtualMachine.h"
15
/* Configuration options */
17
/* Platform specific definitions */
18
#include "sqPlatformSpecific.h"
22
#define null 0 /* using 'null' because nil is predefined in Think C */
23
#ifdef SQUEAK_BUILTIN_PLUGIN
25
// was #undef EXPORT(returnType) but screws NorCroft cc
26
#define EXPORT(returnType) static returnType
29
/* memory access macros */
30
#define byteAt(i) (*((unsigned char *) (i)))
31
#define byteAtput(i, val) (*((unsigned char *) (i)) = val)
32
#define longAt(i) (*((int *) (i)))
33
#define longAtput(i, val) (*((int *) (i)) = val)
37
/*** Proxy Functions ***/
38
#define stackValue(i) (interpreterProxy->stackValue(i))
39
#define stackIntegerValue(i) (interpreterProxy->stackIntegerValue(i))
40
#define successFlag (!interpreterProxy->failed())
41
#define success(bool) (interpreterProxy->success(bool))
42
#define arrayValueOf(oop) (interpreterProxy->arrayValueOf(oop))
43
#define checkedIntegerValueOf(oop) (interpreterProxy->checkedIntegerValueOf(oop))
44
#define fetchArrayofObject(idx,oop) (interpreterProxy->fetchArrayofObject(idx,oop))
45
#define fetchFloatofObject(idx,oop) (interpreterProxy->fetchFloatofObject(idx,oop))
46
#define fetchIntegerofObject(idx,oop) (interpreterProxy->fetchIntegerofObject(idx,oop))
47
#define floatValueOf(oop) (interpreterProxy->floatValueOf(oop))
48
#define pop(n) (interpreterProxy->pop(n))
49
#define pushInteger(n) (interpreterProxy->pushInteger(n))
50
#define sizeOfSTArrayFromCPrimitive(cPtr) (interpreterProxy->sizeOfSTArrayFromCPrimitive(cPtr))
51
#define storeIntegerofObjectwithValue(idx,oop,value) (interpreterProxy->storeIntegerofObjectwithValue(idx,oop,value))
52
#define primitiveFail() interpreterProxy->primitiveFail()
53
/* allows accessing Strings in both C and Smalltalk */
54
#define asciiValue(c) c
58
#define IncrementFractionBits 16
59
#define LoopIndexFractionMask 511
60
#define LoopIndexScaleFactor 512
61
#define ScaleFactor 32768
62
#define ScaledIndexOverflow 536870912
66
#ifdef SQUEAK_BUILTIN_PLUGIN
69
struct VirtualMachine* interpreterProxy;
70
static const char *moduleName =
71
#ifdef SQUEAK_BUILTIN_PLUGIN
72
"SoundGenerationPlugin 19 March 2005 (i)"
74
"SoundGenerationPlugin 19 March 2005 (e)"
78
/*** Function Prototypes ***/
80
EXPORT(const char*) getModuleName(void);
82
static int halt(void);
83
static int msg(char *s);
85
EXPORT(int) primitiveApplyReverb(void);
86
EXPORT(int) primitiveMixFMSound(void);
87
EXPORT(int) primitiveMixLoopedSampledSound(void);
88
EXPORT(int) primitiveMixPluckedSound(void);
89
EXPORT(int) primitiveMixSampledSound(void);
90
EXPORT(int) setInterpreter(struct VirtualMachine* anInterpreter);
94
/* Note: This is hardcoded so it can be run from Squeak.
95
The module name is used for validating a module *after*
96
it is loaded to check if it does really contain the module
97
we're thinking it contains. This is important! */
99
EXPORT(const char*) getModuleName(void) {
103
static int halt(void) {
107
static int msg(char *s) {
108
fprintf(stderr, "\n%s: %s", moduleName, s);
111
EXPORT(int) primitiveApplyReverb(void) {
113
short int *aSoundBuffer;
129
short int *leftBuffer;
130
short int *rightBuffer;
132
rcvr = stackValue(3);
133
aSoundBuffer = arrayValueOf(stackValue(2));
135
startIndex = stackIntegerValue(1);
136
n = stackIntegerValue(0);
137
tapDelays = fetchArrayofObject(7, rcvr);
139
tapGains = fetchArrayofObject(8, rcvr);
141
tapCount = fetchIntegerofObject(9, rcvr);
142
bufferSize = fetchIntegerofObject(10, rcvr);
143
bufferIndex = fetchIntegerofObject(11, rcvr);
144
leftBuffer = fetchArrayofObject(12, rcvr);
146
rightBuffer = fetchArrayofObject(13, rcvr);
148
if (!(successFlag)) {
151
for (sliceIndex = startIndex; sliceIndex <= ((startIndex + n) - 1); sliceIndex += 1) {
152
delayedLeft = delayedRight = 0;
153
for (tapIndex = 1; tapIndex <= tapCount; tapIndex += 1) {
154
i = bufferIndex - (tapDelays[tapIndex]);
158
tapGain = tapGains[tapIndex];
159
delayedLeft += tapGain * (leftBuffer[i]);
160
delayedRight += tapGain * (rightBuffer[i]);
162
j = (2 * sliceIndex) - 1;
163
out = (aSoundBuffer[j]) + (((int) delayedLeft >> 15));
170
aSoundBuffer[j] = out;
171
leftBuffer[bufferIndex] = out;
173
out = (aSoundBuffer[j]) + (((int) delayedRight >> 15));
180
aSoundBuffer[j] = out;
181
rightBuffer[bufferIndex] = out;
182
bufferIndex = (bufferIndex % bufferSize) + 1;
184
if (!(successFlag)) {
187
storeIntegerofObjectwithValue(11, rcvr, bufferIndex);
192
/* Play samples from a wave table by stepping a fixed amount through the table on every sample. The table index and increment are scaled to allow fractional increments for greater pitch accuracy. */
193
/* (FMSound pitch: 440.0 dur: 1.0 loudness: 0.5) play */
195
EXPORT(int) primitiveMixFMSound(void) {
198
short int *aSoundBuffer;
213
short int *waveTable;
214
int scaledWaveTableSize;
217
int normalizedModulation;
218
int scaledOffsetIndex;
219
int scaledOffsetIndexIncr;
221
rcvr = stackValue(5);
222
n = stackIntegerValue(4);
223
aSoundBuffer = arrayValueOf(stackValue(3));
225
startIndex = stackIntegerValue(2);
226
leftVol = stackIntegerValue(1);
227
rightVol = stackIntegerValue(0);
228
scaledVol = fetchIntegerofObject(3, rcvr);
229
scaledVolIncr = fetchIntegerofObject(4, rcvr);
230
scaledVolLimit = fetchIntegerofObject(5, rcvr);
231
count = fetchIntegerofObject(7, rcvr);
232
waveTable = fetchArrayofObject(8, rcvr);
234
scaledWaveTableSize = fetchIntegerofObject(9, rcvr);
235
scaledIndex = fetchIntegerofObject(10, rcvr);
236
scaledIndexIncr = fetchIntegerofObject(11, rcvr);
237
normalizedModulation = fetchIntegerofObject(14, rcvr);
238
scaledOffsetIndex = fetchIntegerofObject(15, rcvr);
239
scaledOffsetIndexIncr = fetchIntegerofObject(16, rcvr);
240
if (!(successFlag)) {
243
doingFM = (normalizedModulation != 0) && (scaledOffsetIndexIncr != 0);
244
lastIndex = (startIndex + n) - 1;
245
for (sliceIndex = startIndex; sliceIndex <= lastIndex; sliceIndex += 1) {
246
sample = ((int) (scaledVol * (waveTable[(((int) scaledIndex >> 15)) + 1])) >> 15);
248
offset = normalizedModulation * (waveTable[(((int) scaledOffsetIndex >> 15)) + 1]);
249
scaledOffsetIndex = (scaledOffsetIndex + scaledOffsetIndexIncr) % scaledWaveTableSize;
250
if (scaledOffsetIndex < 0) {
251
scaledOffsetIndex += scaledWaveTableSize;
253
scaledIndex = ((scaledIndex + scaledIndexIncr) + offset) % scaledWaveTableSize;
254
if (scaledIndex < 0) {
255
scaledIndex += scaledWaveTableSize;
258
scaledIndex = (scaledIndex + scaledIndexIncr) % scaledWaveTableSize;
261
i = (2 * sliceIndex) - 1;
262
s = (aSoundBuffer[i]) + (((int) (sample * leftVol) >> 15));
273
s = (aSoundBuffer[i]) + (((int) (sample * rightVol) >> 15));
282
if (scaledVolIncr != 0) {
283
scaledVol += scaledVolIncr;
284
if (((scaledVolIncr > 0) && (scaledVol >= scaledVolLimit)) || ((scaledVolIncr < 0) && (scaledVol <= scaledVolLimit))) {
285
scaledVol = scaledVolLimit;
291
if (!(successFlag)) {
294
storeIntegerofObjectwithValue(3, rcvr, scaledVol);
295
storeIntegerofObjectwithValue(4, rcvr, scaledVolIncr);
296
storeIntegerofObjectwithValue(7, rcvr, count);
297
storeIntegerofObjectwithValue(10, rcvr, scaledIndex);
298
storeIntegerofObjectwithValue(15, rcvr, scaledOffsetIndex);
303
/* Play samples from a wave table by stepping a fixed amount through the table on every sample. The table index and increment are scaled to allow fractional increments for greater pitch accuracy. If a loop length is specified, then the index is looped back when the loopEnd index is reached until count drops below releaseCount. This allows a short sampled sound to be sustained indefinitely. */
304
/* (LoopedSampledSound pitch: 440.0 dur: 5.0 loudness: 0.5) play */
306
EXPORT(int) primitiveMixLoopedSampledSound(void) {
309
short int *aSoundBuffer;
320
int compositeLeftVol;
321
int compositeRightVol;
330
short int *leftSamples;
331
short int *rightSamples;
334
int scaledLoopLength;
338
rcvr = stackValue(5);
339
n = stackIntegerValue(4);
340
aSoundBuffer = arrayValueOf(stackValue(3));
342
startIndex = stackIntegerValue(2);
343
leftVol = stackIntegerValue(1);
344
rightVol = stackIntegerValue(0);
345
scaledVol = fetchIntegerofObject(3, rcvr);
346
scaledVolIncr = fetchIntegerofObject(4, rcvr);
347
scaledVolLimit = fetchIntegerofObject(5, rcvr);
348
count = fetchIntegerofObject(7, rcvr);
349
releaseCount = fetchIntegerofObject(8, rcvr);
350
leftSamples = fetchArrayofObject(10, rcvr);
352
rightSamples = fetchArrayofObject(11, rcvr);
354
lastSample = fetchIntegerofObject(16, rcvr);
355
loopEnd = fetchIntegerofObject(17, rcvr);
356
scaledLoopLength = fetchIntegerofObject(18, rcvr);
357
scaledIndex = fetchIntegerofObject(19, rcvr);
358
scaledIndexIncr = fetchIntegerofObject(20, rcvr);
359
if (!(successFlag)) {
362
isInStereo = leftSamples != rightSamples;
363
compositeLeftVol = ((int) (leftVol * scaledVol) >> 15);
364
compositeRightVol = ((int) (rightVol * scaledVol) >> 15);
365
i = (2 * startIndex) - 1;
366
lastIndex = (startIndex + n) - 1;
367
for (sliceIndex = startIndex; sliceIndex <= lastIndex; sliceIndex += 1) {
368
sampleIndex = ((int) (scaledIndex += scaledIndexIncr) >> 9);
369
if ((sampleIndex > loopEnd) && (count > releaseCount)) {
370
sampleIndex = ((int) (scaledIndex -= scaledLoopLength) >> 9);
372
if ((nextSampleIndex = sampleIndex + 1) > lastSample) {
373
if (sampleIndex > lastSample) {
375
if (!(successFlag)) {
378
storeIntegerofObjectwithValue(3, rcvr, scaledVol);
379
storeIntegerofObjectwithValue(4, rcvr, scaledVolIncr);
380
storeIntegerofObjectwithValue(7, rcvr, count);
381
storeIntegerofObjectwithValue(19, rcvr, scaledIndex);
386
if (scaledLoopLength == 0) {
387
nextSampleIndex = sampleIndex;
389
nextSampleIndex = (((int) (scaledIndex - scaledLoopLength) >> 9)) + 1;
392
m = scaledIndex & LoopIndexFractionMask;
393
rightVal = leftVal = ((int) (((leftSamples[sampleIndex]) * (LoopIndexScaleFactor - m)) + ((leftSamples[nextSampleIndex]) * m)) >> 9);
395
rightVal = ((int) (((rightSamples[sampleIndex]) * (LoopIndexScaleFactor - m)) + ((rightSamples[nextSampleIndex]) * m)) >> 9);
398
s = (aSoundBuffer[i]) + (((int) (compositeLeftVol * leftVal) >> 15));
409
s = (aSoundBuffer[i]) + (((int) (compositeRightVol * rightVal) >> 15));
419
if (scaledVolIncr != 0) {
420
scaledVol += scaledVolIncr;
421
if (((scaledVolIncr > 0) && (scaledVol >= scaledVolLimit)) || ((scaledVolIncr < 0) && (scaledVol <= scaledVolLimit))) {
422
scaledVol = scaledVolLimit;
425
compositeLeftVol = ((int) (leftVol * scaledVol) >> 15);
426
compositeRightVol = ((int) (rightVol * scaledVol) >> 15);
430
if (!(successFlag)) {
433
storeIntegerofObjectwithValue(3, rcvr, scaledVol);
434
storeIntegerofObjectwithValue(4, rcvr, scaledVolIncr);
435
storeIntegerofObjectwithValue(7, rcvr, count);
436
storeIntegerofObjectwithValue(19, rcvr, scaledIndex);
441
/* The Karplus-Strong plucked string algorithm: start with a buffer full of random noise and repeatedly play the contents of that buffer while averaging adjacent samples. High harmonics damp out more quickly, transfering their energy to lower ones. The length of the buffer corresponds to the length of the string. */
442
/* (PluckedSound pitch: 220.0 dur: 6.0 loudness: 0.8) play */
444
EXPORT(int) primitiveMixPluckedSound(void) {
447
short int *aSoundBuffer;
466
int scaledIndexLimit;
468
rcvr = stackValue(5);
469
n = stackIntegerValue(4);
470
aSoundBuffer = arrayValueOf(stackValue(3));
472
startIndex = stackIntegerValue(2);
473
leftVol = stackIntegerValue(1);
474
rightVol = stackIntegerValue(0);
475
scaledVol = fetchIntegerofObject(3, rcvr);
476
scaledVolIncr = fetchIntegerofObject(4, rcvr);
477
scaledVolLimit = fetchIntegerofObject(5, rcvr);
478
count = fetchIntegerofObject(7, rcvr);
479
ring = fetchArrayofObject(8, rcvr);
481
scaledIndex = fetchIntegerofObject(9, rcvr);
482
scaledIndexIncr = fetchIntegerofObject(10, rcvr);
483
scaledIndexLimit = fetchIntegerofObject(11, rcvr);
484
if (!(successFlag)) {
487
lastIndex = (startIndex + n) - 1;
488
scaledThisIndex = scaledNextIndex = scaledIndex;
489
for (sliceIndex = startIndex; sliceIndex <= lastIndex; sliceIndex += 1) {
490
scaledNextIndex = scaledThisIndex + scaledIndexIncr;
491
if (scaledNextIndex >= scaledIndexLimit) {
492
scaledNextIndex = ScaleFactor + (scaledNextIndex - scaledIndexLimit);
494
average = ((int) ((ring[((int) scaledThisIndex >> 15)]) + (ring[((int) scaledNextIndex >> 15)])) >> 1);
495
ring[((int) scaledThisIndex >> 15)] = average;
497
/* scale by volume */
499
sample = ((int) (average * scaledVol) >> 15);
500
scaledThisIndex = scaledNextIndex;
502
i = (2 * sliceIndex) - 1;
503
s = (aSoundBuffer[i]) + (((int) (sample * leftVol) >> 15));
514
s = (aSoundBuffer[i]) + (((int) (sample * rightVol) >> 15));
523
if (scaledVolIncr != 0) {
524
scaledVol += scaledVolIncr;
525
if (((scaledVolIncr > 0) && (scaledVol >= scaledVolLimit)) || ((scaledVolIncr < 0) && (scaledVol <= scaledVolLimit))) {
526
scaledVol = scaledVolLimit;
531
scaledIndex = scaledNextIndex;
533
if (!(successFlag)) {
536
storeIntegerofObjectwithValue(3, rcvr, scaledVol);
537
storeIntegerofObjectwithValue(4, rcvr, scaledVolIncr);
538
storeIntegerofObjectwithValue(7, rcvr, count);
539
storeIntegerofObjectwithValue(9, rcvr, scaledIndex);
544
/* Mix the given number of samples with the samples already in the given buffer starting at the given index. Assume that the buffer size is at least (index + count) - 1. */
546
EXPORT(int) primitiveMixSampledSound(void) {
549
short int *aSoundBuffer;
570
rcvr = stackValue(5);
571
n = stackIntegerValue(4);
572
aSoundBuffer = arrayValueOf(stackValue(3));
574
startIndex = stackIntegerValue(2);
575
leftVol = stackIntegerValue(1);
576
rightVol = stackIntegerValue(0);
577
scaledVol = fetchIntegerofObject(3, rcvr);
578
scaledVolIncr = fetchIntegerofObject(4, rcvr);
579
scaledVolLimit = fetchIntegerofObject(5, rcvr);
580
count = fetchIntegerofObject(7, rcvr);
581
samples = fetchArrayofObject(8, rcvr);
583
samplesSize = fetchIntegerofObject(10, rcvr);
584
scaledIndex = fetchIntegerofObject(11, rcvr);
585
indexHighBits = fetchIntegerofObject(12, rcvr);
586
scaledIncrement = fetchIntegerofObject(13, rcvr);
587
if (!(successFlag)) {
590
lastIndex = (startIndex + n) - 1;
592
/* index of next stereo output sample pair */
594
outIndex = startIndex;
595
sampleIndex = indexHighBits + (((unsigned) scaledIndex) >> IncrementFractionBits);
596
while ((sampleIndex <= samplesSize) && (outIndex <= lastIndex)) {
597
sample = ((int) ((samples[sampleIndex]) * scaledVol) >> 15);
599
i = (2 * outIndex) - 1;
600
s = (aSoundBuffer[i]) + (((int) (sample * leftVol) >> 15));
611
s = (aSoundBuffer[i]) + (((int) (sample * rightVol) >> 15));
620
if (scaledVolIncr != 0) {
621
scaledVol += scaledVolIncr;
622
if (((scaledVolIncr > 0) && (scaledVol >= scaledVolLimit)) || ((scaledVolIncr < 0) && (scaledVol <= scaledVolLimit))) {
623
scaledVol = scaledVolLimit;
627
scaledIndex += scaledIncrement;
628
if (scaledIndex >= ScaledIndexOverflow) {
629
overflow = ((unsigned) scaledIndex) >> IncrementFractionBits;
630
indexHighBits += overflow;
631
scaledIndex -= overflow << IncrementFractionBits;
633
sampleIndex = indexHighBits + (((unsigned) scaledIndex) >> IncrementFractionBits);
637
if (!(successFlag)) {
640
storeIntegerofObjectwithValue(3, rcvr, scaledVol);
641
storeIntegerofObjectwithValue(4, rcvr, scaledVolIncr);
642
storeIntegerofObjectwithValue(7, rcvr, count);
643
storeIntegerofObjectwithValue(11, rcvr, scaledIndex);
644
storeIntegerofObjectwithValue(12, rcvr, indexHighBits);
649
/* Note: This is coded so that is can be run from Squeak. */
651
EXPORT(int) setInterpreter(struct VirtualMachine* anInterpreter) {
654
interpreterProxy = anInterpreter;
655
ok = interpreterProxy->majorVersion() == VM_PROXY_MAJOR;
659
ok = interpreterProxy->minorVersion() >= VM_PROXY_MINOR;
664
#ifdef SQUEAK_BUILTIN_PLUGIN
667
void* SoundGenerationPlugin_exports[][3] = {
668
{"SoundGenerationPlugin", "primitiveMixFMSound", (void*)primitiveMixFMSound},
669
{"SoundGenerationPlugin", "primitiveMixLoopedSampledSound", (void*)primitiveMixLoopedSampledSound},
670
{"SoundGenerationPlugin", "primitiveMixPluckedSound", (void*)primitiveMixPluckedSound},
671
{"SoundGenerationPlugin", "primitiveMixSampledSound", (void*)primitiveMixSampledSound},
672
{"SoundGenerationPlugin", "getModuleName", (void*)getModuleName},
673
{"SoundGenerationPlugin", "primitiveApplyReverb", (void*)primitiveApplyReverb},
674
{"SoundGenerationPlugin", "setInterpreter", (void*)setInterpreter},
679
#endif /* ifdef SQ_BUILTIN_PLUGIN */