CSC 220.010CPVL
- Object Oriented Multimedia Programming, Fall 2023, Old Main
158.
Assignment 3 is due by 11:59 PM on Thursday
November 9 via D2L.
Read the October
24 doc and listen to the October
24 Zoom recording for changes to STUDENT 3.
Added 10/30
in response to student questions:
All of the instructions are in the
STUDENT tab along with most of the work.
There are instructions in Student for
adding a constructor call loop in setup() and
changing a couple
Globey functions. I recommend testing after each STUDENT
step.
I prefer that you zip the entire folder including
all image files and your .pde files into a regular .zip file and
turn that in, NOT a .7z or some other format. You
may be able to turn in a directory. If you cannot do either,
then turn in individual files named CSC220F23Assn3_MIDI.pde,
MIDI.pde, STUDENT.pde, Parson.pde and Globey.pde, along
with any image files in your project. Please removed spaces
from the image file names. I will deduct 10
points for .pde files with different names from these or image
files containing spaces, because unpacking (40 students X 7 or
more) = 280 files with rando names would take me all day.
Thanks!
We are going to do a variant of last years MIDI
assignment of exploding HayBales that uses imploding Globeys.
Here is a link to a video showing my solution.
Here is the Javadoc for javax.sound.midi.ShortMessage,
and for the MIDI
Fanatic documentation, see "The MIDI Specification" and
"General MIDI (GM)".
Here is the code for ConcentricCirclesIntervals
that you can use to explore:
PROGRAM_CHANGE (left and right arrows) to try
out instrument patches.
CONTROL_CHANGE (cN gives you controller N and
fL sets its level L from 0 to 127).
STEP 1. Load the linked main code tab into
a new Processing sketch and save it as sketch CSC220F23Assn3_MIDI.
STEP 2. Create a new named tab in the Processing IDE and
paste the tab's starting code into it, saving after each step.
Tab
MIDI
Tab STUDENT
Tab Parson
Tab Globey
Save my TriTexture.jpg into your
sketch directory for texturing my custom PShape.
You do not have a custom
PShape requirement in this assignment.
STEP 3. Follow these instructions in the STUDENT tab.
Some require edits in the main CSC220F23Assn3_MIDI and Globey
tabs, but the instructions are in STUDENT.
Test after every STUDENT step. Do not try to
code everything and then test.
From the STUDENT tab comments:
// All STUDENT instructions are in this tab. TEST AFTER EACH
STUDENT STEP!!!
// STUDENT AVATAR & any extra variables for it go in STUDENT
tab unless otherwise noted.
// This is due via D2L Assignment 3 at the end of Thursday
November 9.
// STUDENT 1 (10%) Copy your Avatar class (nothing else)
into this tab and add constructor
// calls in the setup() function in the main tab within this loop.
//for (int i = avatars.length/2-2 ; i < avatars.length ;
i++) {
// // STUDENT 1 construct your avatars in
this loop.
//}
// Test that your avatar displays and moves properly before STEP
2.
// STUDENT 2 (10%) The constructor parameters should not
need to change from Assignment 2.
// There are no new arguments. The MIDI instrument, channel, and
other MIDI properties are
// defined inside my Professor class and will be inside your class
after it displays.
// Class Professor is in tab Parson. Here are the MIDI data fields
at the top of the class.
// You can come up with only one OR more than 1 instrument for
your avatar.
//int ProfessorScaleStep = 0 ;
//int ProfessorTimeDelaySlot = 0 ;
//class Professor extends CollisionDetector {
// /* The data fields store the state of the Avatar. */
// protected int legdist = 0 ; // You can initialize to a
constant here.
// int channel = 0 ; // Your Avatar MUST use channel 10.
// int mypitch = 0 ;
// float mydelay = 0 ;
// float [] delaySeconds = {.1, .15, .25}; IGNORE THE DELAY
// I stopped using the delay and switched to making sound
upon collisions.
// int instrument = 106 ; //
http://midi.teragonaudio.com/tutr/gm.htm
// and in the constructor code:
//int [] myscale = scales[2]; // major
scale
//mypitch = myscale[ProfessorScaleStep] +
48 ;
//// major scale, next note in scale, halfway
up keyboard
//ProfessorScaleStep = (ProfessorScaleStep + 1)
% myscale.length ;
//mydelay =
delaySeconds[ProfessorTimeDelaySlot]; STUDENT IGNORE
DELAY
//instrument += ProfessorTimeDelaySlot ;
// You can come up with only one OR more than 1
instrument for your avatar.
//ProfessorTimeDelaySlot =
(ProfessorTimeDelaySlot + 1) % delaySeconds.length ;
// I used two global variables ProfessorScaleStep and
ProfessorTimeDelaySlot defined
// just outside the class to vary the note (mypitch) instrument,
and timing
// (mydelay) for each newly constructed Professor object. Normally
a Java "class static"
// variable inside the class would have only 1 value shred by all
objects of that class,
// but the Processing framework disallows class static variables
for framework
// implementation reasons, so I put them outside the class.
// Your Avatar MUST use channel 10 (I am using 0 and 1 and
reserving the others),
// a range of instruments away from my 106 and its neighbors (see
// // http://midi.teragonaudio.com/tutr/gm.htm ) or explore with
ConcentricCirclesInterval sketch.
// STUDENT 3 (50%) All of my Professor's MIDI function
calls are inside its move() function.
// Note that detectCollisions() now returns a java.util.Set object
containing
// all of the colliding Avatar objects, if any, including bales of
Globey objects.
// Use this code from detectCollisions()'s return value to sonify
collisions.
// Use your own new or added CONTROL_CHANGEs or other MIDI
messages, e.g., 2 notes at a time.
//Set<Avatar> colliders =
detectCollisions();
//if (colliders.size() > 0) {
// sendMIDI(ShortMessage.PROGRAM_CHANGE,
channel, instrument, 0);
// int volumeAdjust = 7 ;
// sendMIDI(ShortMessage.CONTROL_CHANGE,
channel, volumeAdjust, 127);
// int balanceControl = 8 ;
// int balanceLocation =
int(constrain(map(myx, 0, width, 0, 127),0,127)); // 64 is
centered in stereo field
// sendMIDI(ShortMessage.CONTROL_CHANGE,
channel, balanceControl, balanceLocation);
// sendMIDI(ShortMessage.NOTE_ON,
channel, mypitch, 127);
// // See
http://midi.teragonaudio.com/tech/midispec.htm
//}
//for (Avatar other : colliders) {
// float probability = random(0, 100);
// if (probability < 60) { // mow 60%
of them
// other.mow();
// }
//}
// 3a. CHANGE the probability if mow()ing a
Globey from 60% to something else. Play around with values.
// 3b. Add a CONTROL_CHANGE MIDI effect
that you can hear, see
// http://midi.teragonaudio.com/tech/midispec.htm
and experiment with ConcentricCirclesInterval sketch.
// Take a listen to modulation wheel
(controller 1) and chorus (controller 93) Note that unlike the
// instrument numbers, these start at 0, i.e.,
mod wheel is 1, bank select is 0. Make it a mapped
// function of y location relative to [0,
height-1] or another avatar varying variable.
// 3c. Add a second CONTROL_CHANGE MIDI
effect that you can hear. Make it a mapped function
// of z location relative to minimumZ and
maximumZ or anotehr avara varying variable.
// STUDENT 4 (30%) Make an imploding Globey similar
to a video I will post.
// Here is what I did for the video:
// 4a. changed this in Globey's mow() function:
// void mow() {
// avatars[avatarsIndex] = null ;
// GlobeyCount = constrain(GlobeyCount-1, 0,
GlobeyCount);
// // println("DEBUG GlobeyCount GlobeyMAX",
GlobeyCount, GlobeyMax);
// if (GlobeyCount == 0) {
// sendMIDI(ShortMessage.NOTE_OFF,
channel, pitch, 0);
// }
//}
// TO THIS:
//void mow() {
// mowCounter += 1 ;
//}
// I initialized the "int mowCounter = 0" code in the top
of class Globey.
// 4b. The move() function in Globey now does the
following pseudo-code:
// If the mowCounter is greater than 0
// Add 1 to mowCounter
// If mowScaleXYZ is a value
very close to 0.0 (it may never reach 0).
// Do the steps
previously in Globey.mow(), i.e., null this object's avatars[]
entry
// and send the
NOTE_OFF if the decrement GlobeyCount <= 0.
// 4c. In Globey.display, immediately after
translate, if the mowCounter is greater than 0,
// scale(mowScaleXYZ),
where mowScaleXYZ is initialized to 1.0 in the constructor.
// Then, still within
the "if the mowCounter is greater than 0" scope,
// decrement
mowScaleXYZ by some tiny but vsible amount. This will shrink the
sphere.
// See step 4b above
for when mowScaleXYZ approaches 0. I played around with
shrinkage
// decerements and the
boundary for sphere disappearance in step 4b.
// THE SCALE MUST MAKE
THE GLOBEY SHRINK ***SLOWLY***, NOT EXPLODE!!!
// Basically, you want the
scale in this step to approach 0 slowly, and when it is
// close to 0 (invisible in
at least 1 dimension), do the step 4.b removal with NOTE_OFF.
// You should leave the
bounding box for the sphere full size as it shrinks,
// in order to keep a higher
probability of collision.
// 4d. In the Globey tab change this line of code in
makeglobePShape():
// globePImage =
loadImage("clover.png");
// to load a .jpg or .png
supplied by you. Make sure to include that image
// file in your project directory
and turn it in to D2L with ALL YOUR CODE .pde files,
// preferrabbly as a regular .zip
file.
// Then do the following as given
in makeglobePShape():
// STUDENT set the texture on this PShape to
globePImage.
// See calls to setTexture(t) in
//
https://faculty.kutztown.edu/parson/fall2022/CSC220FA2022DemoSome3D.txt
// If you use an image off the web with no copyright
restriction, cite its URL in a command.