Diese JSL erstellt ein Video zu etwas Musik.Normalerweise wäre es umgekehrt: Die Musik würde passend zum Video ausgewählt.Indem ich zuerst die Musik auswähle und ein wenig beschränke, wie das Video aussehen kann, erhalte ich eine Reihe von Bildern, die mit dem Audio kombiniert werden können (in diesem Fall mithilfe von Blender), um eine perfekte Synchronisierung zu erzielen.Auch hier ist die JSL nicht bereinigt, aber es sind einige Kommentare darin verstreut.
DoNotEat – YouTube

wav = "44.1KHz 16bit stereo.wav"; // this is the music file
//Open( wav ); // we'll get back to the music after a bit. for now, start it playing.
// here's *some* of the parameters that were lifted out of the JSL as it was
// developed, moved up front to be easier to change
resolution = 120; // 20 makes a fast render but a less smooth appearance. 120 is slow and pretty
// this is the dimension of the mesh that creates the shape of the lumps. doesn't seem to affect speed.
dim = 30; // believe 30 is a limitation on win opengl. needs to be even number.
// the 1920*1080 video size is still inline, but this made it possible to scale it to twice the size and
// let Blender scale it back down, probably smoothing out some jaggies...anti-aliasing...
picscale = .5;//2;//
// initial rotation of the scene. Later these numbers will be changed, a little, as the images are generated.
yrot = 188; // +/- 20
xrot = 68; // +/- 20
zrot = -310; // this can rotate continuously
// make some extra images at the beginning before the audio; this audio file has no leading silence
preroll = 10;
// this was taken from the teapot example that ships with JMP, and modified a lot. Some names stuck.
// in the teapot, a patch was a 4x4 matrix of numbers. Here it is 30x30 (dim, above)
// this could be *way* simpler if you don't need it to be pretty...this is all about smoothness.
patch = Function( {dent}, // -1<=dent<=1
xpoints = J( dim, dim, 0 );
ypoints = J( dim, dim, 0 );
zpoints = J( dim, dim, 0 );
// build the smooth 3D shape
// in the 30x30 square grid there are 15 concentric (square) rings to place in the desired sheet
// for each point in the 30x30 grid, the ring number is determined by the distance to the
// edge of the row or col closest to the edge
bottom = 0; // starting here...trial and error to get a pleasing shape
top = (dim / 2) - 1; // can't explain it because it is a week later...
center = (dim + 1) / 2; // NOTE: the 30x30 x,y,z coordinates are
scale = 5; // control points...they DO NOT LIE on the surface
For( row = 1, row <= dim, row++,
For( col = 1, col <= dim, col++,
ring = Interpolate( Min( row - 1, col - 1, dim - row, dim - col ), bottom, 0.001, top, Pi() );
ypoints[row, col] = scale * Sin( ring ) * (row - center) / dim;
xpoints[row, col] = scale * Sin( ring ) * (col - center) / dim;
zpoints[row, col] = Interpolate( ring, 0, .9, // low values of ring are the folded-under corners of the
.7, 1, // sheet. .9 actually punches back up slightly from the base at 1.
1.8, -.5, // mid values of ring from .7 to 1.8 map further negative
// ring from 1.8 to PI runs from -.5 to either -2 (big bump for negative dent) or
// +1.8 (big dent for positive dent) with 0 dent adjusted to -.3 to look flat
Pi(), Interpolate( -dent, -1, -2, 0, -.3, 1, 1.8 ) // maxdented=1.8 -.3=centered bumped=-2
);
)
);
// build the combined points matrix. shape() converts the 30x30 matrix into 900x1
// and the 3 900x1 matrixes are joined into a 900x3
points = Shape( ypoints, dim * dim, 1 ) || Shape( xpoints, dim * dim, 1 ) || Shape( zpoints, dim * dim, 1 );
// the MAP2 method adds the control points. The WWW examples rarely explain the MAP2
// parameters in detail; I think I've got this mostly right, especially for a square case (xDim==yDim)
Teapot << Map2( MAP2_VERTEX_3, 0, 1, N Cols( points ), Sqrt( N Rows( points ) ),
0, 1, N Cols( points ) * Sqrt( N Rows( points ) ), Sqrt( N Rows( points ) ), points );
// the EVALMESH2 method creates polygons with normal vectors using the resolution to
// determine the number of polygons
Teapot << EvalMesh2( FILL, 0, resolution, 0, resolution );
);
// pre-build a set of objects. Call the above function, a bunch of times, with a range of values from -1 to 1
// the objects are 3D display lists that can be reused. No color is assigned yet.
nobj = 240;// creates 2N+1 discrete levels. turns out to be not important exactly how many.
obj = Associative Array(); // to hold the display list objects
For( dent = -nobj, dent <= nobj, dent += 1,
teapot = Scene Display List();
patch( dent / nobj );
obj[dent] = teapot;
);
// make the main 3D displaylist box. To make the video not have a white border line I had to
// add 1. Later you'll see where the border is removed
scene = Scene Box( picscale * 1920 + 1, picscale * 1080 + 1 );
New Window( "Teapot",
V List Box(
scene, // the sliders were used to figure out what rotations I
Slider Box( -360, 360, xrot, buildscene(), <<SETWIDTH> real + imag :*</img> imag ); // just the amplitude
time = (i - 1) * (cols / 44100); // unused?
maxa = Max( maxa, Max( ampl ) );
);
// do it again, this time make the pics using the maxs and maxa
i = 1;
zrot = zrot - preroll * .25;
{real, imag} = FFT( {x[i, 0]`} );
ampl = Sqrt( real :*</img> real + imag :*</img> imag ); // just the amplitude
amplFiltered = ampl * 0.00001;
// make preroll lead-in frames before the audio;
For( i = -preroll, i < 1, i++,
buildscene();
Wait( 0 );
pic = scene << getpicture;
pixels = pic << getpixels;
pixels = pixels[2 :: picscale * 1080 + 1, 3 :: picscale * 1920 + 2];
pic << setpixels( pixels );
pic << saveimage( "$temp\m" || Right( Char( i + preroll, 9 ), 9, "0" ) || ".png" );
amplFiltered = ampl * Interpolate( i, -preroll, 0.00001, -preroll / 5, 0.0001, 1, 1 );
);
// make the frames from the filtered FFT results. the filter allows fast rise but slow decay
For( i = 1, i <= rows, i++,
Print( i / rows ); // each for is a video frame and 1/30 second of audio
{real, imag} = FFT( {x[i, 0]`} ); // FFT the row
ampl = Sqrt( real :*</img> real + imag :*</img> imag ); // just the amplitude
time = (i - 1) * (cols / 44100); // unused
amplFiltered = If( i == 1,
ampl,
selector = Greater( ampl, amplFiltered );
selector :*</img> ampl + (1 - selector) :*</img> ((3 * amplFiltered + ampl) / 4);
);
buildscene();
Wait( 0 );
pic = scene << getpicture;
pixels = pic << getpixels;
// here's the clipping of the unwanted border pixels...
// the exact offsets may need to be rediscovered sometime if JMP or OS changes something
pixels = pixels[2 :: picscale * 1080 + 1, 3 :: picscale * 1920 + 2];
pic << setpixels( pixels );
// Blender works well with a directory of files x00001.png, x00002.png, ...
pic << saveimage( "$temp\m" || Right( Char( i + preroll, 9 ), 9, "0" ) || ".png" );
);
// dead frames at end ramp down the amplitude...
For( i, i < rows + 360, i++, // trailer
amplFiltered = amplFiltered :*</img> .95;
buildscene();
Wait( 0 );
pic = scene << getpicture;
pixels = pic << getpixels;
pixels = pixels[2 :: picscale * 1080 + 1, 3 :: picscale * 1920 + 2];
pic << setpixels( pixels );
pic << saveimage( "$temp\m" || Right( Char( i + preroll, 9 ), 9, "0" ) || ".png" );
);
,
Print( "bad file" )
);
Print( "done" );
</SETWIDTH>
19. Juni 2019: Die JSL wurde nach dem Community-Wechsel vor einigen Jahren endlich repariert