home *** CD-ROM | disk | FTP | other *** search
- /* VU.C VU Meter for the Sampler
-
- (c) 1987 Todor Fay
-
- LATTICE C version:
-
- lc1 vu
- lc2 -v vu
- atom vu.o ram:foo -cd
- copy ram:foo vu.o
- blink with vu.with
- */
-
- #include "exec/exec.h"
- #include "exec/types.h"
- #include "soundscape.h"
- #include "intuition/intuition.h"
-
- /* Images for the LEDs. A red LED for lighting,
- a blue LED for turning it back off
- (the background color.)
- */
-
- UWORD redleddata[] = { /* 16 x 3 */
- 65535,
- 65535,
- 65535,
- 65535,
- 65535,
- 65535,
- };
-
- struct Image redledimage = { 0,0,16,3,2,redleddata,3,0,0 };
-
- UWORD blueleddata[] = { /* 16 x 3 */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- };
-
- struct Image blueledimage = { 0,0,16,3,2,blueleddata,3,0,0 };
-
- /* We don't need any Intuition Gadgets, just a
- window to display the LEDs in.
- This was designed with Power Windows.
- */
-
- struct NewWindow NewWindowStructure = {
- 0,0,
- 250,20,
- 0,1,
- NULL,
- WINDOWDRAG+WINDOWDEPTH,
- NULL,
- NULL,
- "VU Meter",
- NULL,
- NULL,
- 5,5,
- 0,0,
- WBENCHSCREEN
- };
-
- short thisport; /* This port's id. */
- long SoundScapeBase; /* SoundScape library. */
- long IntuitionBase;
-
- /* We need a place to store the Sampler's
- output routine address, since we are replacing
- the code pointer in its port structure
- with our own.
- */
-
- void (*sampleroutcode) ();
- struct Window *vuwindow; /* Display window. */
-
- /* We need an array of velocity values for each
- note that is being played. These are zeroed
- for no note.
- If you add up all the velocities in this
- array, you should get totalvolume, which
- is used to determine the number of LEDs to
- light.
- */
-
- unsigned char velocity[128];
- unsigned short totalvolume;
-
- insertoutcode(note)
-
- /* This output routine is not given to the Patch
- Panel in the AddMidiPort call. Instead, this
- routine replaces the Sampler output code, and
- then calls it. So, this is inserted there by
- the open routine.
-
- Check the note status. If it is NOTEON or NOTEOFF,
- we want to use it for the display.
-
- Start by decrementing the totalvolume by
- velocity[note->value]. If this is a NOTEOFF
- event, this reduces totalvolume appropriately.
- If this is a NOTEON event, this clears any
- previous NOTEON that was stored. This is
- neccessary because we aren't supporting multiple
- playing of the same note (for simplicity.)
-
- If this is a NOTEON event, increment totalvolume
- by the velocity of this note. Store this
- velocity in the velocity array.
-
- Else, for a NOTEOFF event, simply put zero in
- the velocity array - there is no note being
- played.
-
- Compute how many LEDs should be on from
- totalvolume. Each additional LED represents
- a doubling in volume, so figure what the most
- significant bit of totalvolume is.
-
- If the new top LED position (newvupos) is
- greater than the currently displayed one
- (vupos), draw in the extra LEDs. Else,
- if newvupos is less than vupos, erase
- LEDs down to newvupos.
-
- Finally, forward the note event to the
- Sampler by calling its output routine.
- */
-
- struct Note *note;
-
- {
- unsigned char status = note->status & 0xF0;
- static short vupos = 0;
- short newvupos, index;
- if (sampleroutcode) {
- if ((status == NOTEON) || (status == NOTEOFF)) {
- totalvolume -= velocity[note->value];
- if ((status == NOTEON) && note->velocity) {
- totalvolume += note->velocity;
- velocity[note->value] = note->velocity;
- }
- else velocity[note->value] = 0;
- newvupos = 0;
- index = 4;
- for (;index < totalvolume; index = index << 1)
- newvupos++;
- if (newvupos < vupos) {
- for (;vupos > newvupos; vupos--)
- DrawImage(vuwindow->RPort,
- &blueledimage,-10 + vupos * 20,13);
- }
- else if (newvupos > vupos) {
- vupos++;
- for (;vupos <= newvupos; vupos++)
- DrawImage(vuwindow->RPort,
- &redledimage,-10 + vupos * 20,13);
- }
- vupos = newvupos;
- }
- (*sampleroutcode) (note);
- }
- else FreeNode(note);
- }
-
- outcode(note)
-
- /* This, the outcode for this module, does
- nothing.
- */
-
- struct Note *note;
-
- {
- FreeNode(note);
- }
-
-
- opencode(direction)
-
- /* This installs the VU meter.
-
- If this is to install the output routine:
-
- Get the Port structure for the Sampler.
- If the Sampler already has its output
- code stolen, (samplerport->show has somebody's
- port id) do nothing. Else, open the window,
- give samplerport->outcode insertoutcode
- and put the Sampler's output code
- in samplercode. Set samplerport->show to
- this port's id, so no other module will
- monkey with it.
- */
-
- char direction;
-
- {
- short i;
- struct Port *samplerport;
- if (!direction) {
- samplerport = (struct Port *)
- MidiPort(FindMidiPort("sampler"));
- if (samplerport) {
- if (samplerport->show) {
- CloseMidiPort(samplerport->show,0);
- }
- if (!samplerport->show) {
- vuwindow = (struct Window *)
- OpenWindow(&NewWindowStructure);
- if (vuwindow) {
- totalvolume = 0;
- for (i=0; i < 128; i++)
- velocity[i] = 0;
- sampleroutcode = samplerport->outcode;
- samplerport->outcode = insertoutcode;
- samplerport->show = thisport;
- return(1);
- }
- }
- }
- }
- return(0);
- }
-
-
- closecode(direction)
-
- /* This deactivates the VU Meter.
-
- Simply return the Sampler's output routine
- to its Port structure and clear
- samplerport->show. Close the display
- window.
- */
-
- {
- struct Port *samplerport;
- if (!direction) {
- samplerport = (struct Port *)
- MidiPort(FindMidiPort("sampler"));
- if (samplerport && sampleroutcode) {
- samplerport->outcode = sampleroutcode;
- samplerport->show = 0;
- }
- if (vuwindow) CloseWindow(vuwindow);
- vuwindow = 0;
- }
- return(1);
- }
-
- /* The main program is standard with one addition:
- After installing this port, call OpenMidiPort
- to activate it. This is needed because there
- is no icon for the user to click on. We
- could have added that icon, but it would be
- one more item on the Patch Panel, cluttering
- it and causing some confusion since nothing
- can be sent directly to it.
- There is a chance OpenMidiPort will fail. This
- is because the Sampler's output routine was
- already stolen. If so, there is no need to
- stick around, so call RemoveMidiPort and leave.
- Normally, RemoveMidiPort is done by SoundScape
- when it closes down, but this time we'll
- do it ourselves to get out early.
- */
-
- main() {
- IntuitionBase = OpenLibrary("intuition.library",0);
- SoundScapeBase = OpenLibrary("soundscape.library",0);
- if (SoundScapeBase) {
- CloseLibrary(SoundScapeBase);
- thisport = AddMidiPort(opencode,closecode,0,
- outcode,0,0,-1,"vu meter");
- if (OpenMidiPort(thisport,0)) {
- SetTaskPri(FindTask(0),-20);
- while (MidiPort(thisport)) Delay(100);
- }
- else RemoveMidiPort(thisport);
- }
- CloseLibrary(IntuitionBase);
- }
-