/* returns the rotation quat required to match v1 to v2 */ void vects_to_quat(double v1[3], double v2[3], double q[4]){ double axis[3]; double phi; double denom; /* first normalise each of em */ vnormal(v1); vnormal(v2); /* check that someone isn't playing silly buggers */ if((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2])){ vcopy(axis, v1); phi = 0.0; } else{ /* find the axis with a cross product */ vcross(axis, v2, v1); /* find the angle to rotate around that axis. */ /* v1.v2 = ||v1|| ||v2|| cos(angle) */ denom = vlength(v1) * vlength(v2); if(denom == 0){ phi = 0.0; } else{ phi = acos(vdot(v1, v2) / denom); } } /* create the quat */ axis_to_quat(axis, phi, q); }
void quat_to_axis_angle(const Quat p, Vec4f axis, float* angle) { Quat q; quat_copy(p, q); quat_normalize(q, q); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised *angle = (float)(2.0 * acos(q[3])); double s = sqrt(1.0 - q[3] * q[3]); // assuming quaternion normalised then w is less than 1, so term always positive. if( s < CUTE_EPSILON ) { // test to avoid divide by zero, s is always positive due to sqrt // if s close to zero then direction of axis not important axis[0] = q[0]; // if it is important that axis is normalised then replace with x=1; y=z=0; axis[1] = q[1]; axis[2] = q[2]; axis[3] = 1.0; } else { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma warning(push) #pragma warning(disable : 4244) axis[0] = q[0] / s; // normalise axis axis[1] = q[1] / s; axis[2] = q[2] / s; axis[3] = 1.0; #pragma warning(pop) #pragma GCC diagnostic pop } float length = vlength(axis); if( length < CUTE_EPSILON ) { *angle = 0.0f; } }
/* * Ok, simulate a track-ball. Project the points onto the virtual * trackball, then figure out the axis of rotation, which is the cross * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) * Note: This is a deformed trackball-- is a trackball in the center, * but is deformed into a hyperbolic sheet of rotation away from the * center. This particular function was chosen after trying out * several variations. * * It is assumed that the arguments to this routine are in the range * (-1.0 ... 1.0) */ static void trackball ( float q[4], float p1x, float p1y, float p2x, float p2y ) { float a[3]; /* Axis of rotation */ float phi; /* how much to rotate about axis */ float p1[3], p2[3], d[3]; float t; if (p1x == p2x && p1y == p2y) { // Zero rotation vzero(q); q[3] = 1.0; return; } // First, figure out z-coordinates for projection of P1 and P2 to // deformed sphere vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y)); vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y)); // Now, we want the cross product of P1 and P2 vcross(p2,p1,a); // Figure out how much to rotate around that axis. vsub(p1,p2,d); t = vlength(d) / (2.0*TRACKBALLSIZE); // Avoid problems with out-of-control values... if (t > 1.0) t = 1.0; if (t < -1.0) t = -1.0; phi = 2.0 * asin(t); axis_to_quat(a,phi,q); }
void Trackball :: spin ( float friction ) { const int RENORMCOUNT = 97 ; static int count=0; //float * q1, * q2, * dest ; float q1[4], * q2, * dest ; float t1[4], t2[4], t3[4]; float tf[4]; //q1 = m_lastquat ; if( friction != 1.0 ) { float temp ; temp = vlength(m_lastquat); if( temp != 0 ) { vcopy(m_lastquat,q1); vnormal(q1) ; temp = asin(temp)*friction ; q1[0] *= sin(temp) ; q1[1] *= sin(temp) ; q1[2] *= sin(temp) ; q1[3] = cos(temp) ; } else { vcopy(m_lastquat,q1); q1[3] = m_lastquat[3] ; } } else { vcopy(m_lastquat,q1); q1[3] = m_lastquat[3] ; } q2 = m_currquat ; dest = m_currquat ; vcopy(q1,t1); vscale(t1,q2[3]); vcopy(q2,t2); vscale(t2,q1[3]); vcross(q2,q1,t3); vadd(t1,t2,tf); vadd(t3,tf,tf); tf[3] = q1[3] * q2[3] - vdot(q1,q2); dest[0] = tf[0]; dest[1] = tf[1]; dest[2] = tf[2]; dest[3] = tf[3]; if (++count > RENORMCOUNT) { count = 0; normalize_quat(dest); } }
void vnormalize( triple* x ){ f32 len = vlength( x ); if( len == 0 ){ x->x = 0; x->y = 0; x->z = 1; }else{ len = (f32)1.0 / len; vscale( x, len ); } }
/* Split contours so that each length is at most the second argument (length). */ vector<ContourEQW> splitContours(vector<ContourEQW>& contours, int length) { vector<ContourEQW> splitted; for(int i=0; i<contours.size(); ++i) { int m = contours[i].size()/length; int rem = contours[i].size() % length; m++; //figure out how to split a contour of length m vector<int> vlength(m, 0); int dif = contours[i].size() - m * length; float inc = (float)dif / (float)vlength.size(); float sum = 0; int total = 0; for(int k=0; k<vlength.size(); ++k) { sum += inc; vlength[k] = length + (int)sum; sum -= (int)sum; total += vlength[k]; } if(total > contours[i].size()) //this case may happen due to rounding error { vlength[0] -= (total - contours[i].size()); } int acc = 0; float gap = 1.0e-3; for(int j=0; j<m; ++j) { ContourEQW c = extractContourFragment(contours[i], acc, acc+vlength[j]-1); if(c.size()>=2) { //add a little gap to the end points so that we will have different view angle at the shared point. int sz = c.size(); c.X[0] += (c.X[1]>c.X[0]) ? gap: -gap; c.Y[0] += (c.Y[1]>c.Y[0]) ? gap: -gap; c.X[sz-1] += (c.X[sz-2]>c.X[sz-1]) ? gap: -gap; c.Y[sz-1] += (c.Y[sz-2]>c.Y[sz-1]) ? gap: -gap; } splitted.push_back(c); acc += vlength[j]; } } return splitted; }
/* * Ok, simulate a track-ball. Project the points onto the virtual * trackball, then figure out the axis of rotation, which is the cross * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) * Note: This is a deformed trackball-- is a trackball in the center, * but is deformed into a hyperbolic sheet of rotation away from the * center. This particular function was chosen after trying out * several variations. * * It is assumed that the arguments to this routine are in the range * (-1.0 ... 1.0) */ void trackball( double q[4], double p1x, double p1y, double p2x, double p2y ) { double a[3]; /* Axis of rotation */ double phi; /* how much to rotate about axis */ double p1[3], p2[3], d[3]; double t; if( p1x == p2x && p1y == p2y ) { /* Zero rotation */ vzero( q ); q[3] = 1.0; return; } /* * First, figure out z-coordinates for projection of P1 and P2 to * deformed sphere */ vset( p1, p1x, p1y, tb_project_to_sphere( TRACKBALLSIZE, p1x, p1y ) ); vset( p2, p2x, p2y, tb_project_to_sphere( TRACKBALLSIZE, p2x, p2y ) ); /* * Now, we want the cross product of P1 and P2 */ vcross(p2,p1,a); /* * Figure out how much to rotate around that axis. */ vsub( p1, p2, d ); t = vlength( d ) / (2.0f * TRACKBALLSIZE); /* * Avoid problems with out-of-control values... */ if( t > 1.0 ) t = 1.0; if( t < -1.0 ) t = -1.0; phi = 2.0f * (double) asin( t ); axis_to_quat( a, phi, q ); }
/* Ok, simulate a track-ball. Project the points onto the virtual * trackball, then figure out the axis of rotation, which is the cross * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) * Note: This is a deformed trackball-- is a trackball in the center, * but is deformed into a hyperbolic sheet of rotation away from the * center. This particular function was chosen after trying out * several variations. * * It is assumed that the arguments to this routine are in the range * (-1.0 ... 1.0) */ void trackball(double q[4], double p1x, double p1y, double p2x, double p2y){ double axis[3]; /* Axis of rotation */ double phi; /* how much to rotate about axis */ double p1[3], p2[3], d[3]; double t; /* if zero rotation */ if(p1x == p2x && p1y == p2y){ vset(q, 0.0, 0.0, 0.0); q[3] = 1.0; return; } /* First, figure out z-coordinates for projection of P1 and P2 to */ /* the deformed sphere */ p1[0] = p1x; p1[1] = p1y; p1[2] = tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y); p2[0] = p2x; p2[1] = p2y; p2[2] = tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y); /* Now, we want the cross product of P1 and P2 */ vcross(axis, p2, p1); /* Figure out how much to rotate around that axis. */ vsub(d, p1, p2); t = vlength(d)/(2.0*TRACKBALLSIZE); /* Avoid problems with out-of-control values. */ if(t > 1.0){ t = 1.0; } if(t < -1.0){ t = -1.0; } phi = 2.0 * asin(t); axis_to_quat(axis, phi, q); }
/* * Ok, simulate a track-ball. Project the points onto the virtual * trackball, then figure out the axis of rotation, which is the cross * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) * Note: This is a deformed trackball-- is a trackball in the center, * but is deformed into a hyperbolic sheet of rotation away from the * center. This particular function was chosen after trying out * several variations. * * It is assumed that the arguments to this routine are in the range * (-1.0 ... 1.0) */ void trackball(float q[4], float p1x, float p1y, float p2x, float p2y, float tbSize) { float a[3]; // Axis of rotation float phi; // how much to rotate about axis float p1[3], p2[3], d[3]; float t; if( p1x == p2x && p1y == p2y ) { /* Zero rotation */ vzero(q); q[3] = 1.0; return; } // First, figure out z-coordinates for projection of P1 and P2 to deformed sphere vset( p1, p1x, p1y, tb_project_to_sphere(tbSize, p1x, p1y) ); vset( p2, p2x, p2y, tb_project_to_sphere(tbSize, p2x, p2y) ); // Now, we want the cross product of P1 and P2 vcross( p2, p1, a); // Figure out how much to rotate around that axis vsub( p1, p2, d); t = vlength(d) / ( 2.0f * tbSize ); // Avoid problems with out-of-control values if (t > 1.0) { t = 1.0; } if (t < -1.0) { t = -1.0; } phi = 2.0f * (float)asin(t); axis_to_quat( a, phi, q ); }
static void addMeasurement(Packet_t *packet) { xvector[vectorPos] = packet->accX; yvector[vectorPos] = packet->accY; zvector[vectorPos] = packet->accZ; vectorPos++; if (vectorPos < NUM_SAMPLES) return; vectorPos = 0; float s = stdev(xvector) + stdev(yvector) + stdev(zvector); // PRINTF("stdev = %u\n", (uint16_t) s); float accelVector[3] = { average(xvector) - groundVector[0], average(yvector) - groundVector[1], average(zvector) - groundVector[2] }; // PRINTF("accel=(%d %d %d)\n", (int)accelVector[0], (int)accelVector[1], (int)accelVector[2]); bool nowFwd, nowBack; float accLen = vlength(accelVector); if (accLen < ONE_G / 10) { nowBack = nowFwd = false; } else { normalizeQuick(accelVector, accLen); nowFwd = sameDirection(fwdVector, accelVector); nowBack = inverseDirection(fwdVector, accelVector); } int now = nowFwd ? 1 : (nowBack ? -1 : 0); bool diffFromPrevious; static bool notFirstTime; if (notFirstTime) { // float difference = (calcDiff(xvector, prevxvector) // + calcDiff(yvector, prevyvector) // + calcDiff(zvector, prevzvector)) / 3.0; float difference = calcDiff(xvector, prevavgxvector) + calcDiff(yvector, prevavgyvector) + calcDiff(zvector, prevavgzvector); // PRINTF("difference=%d\n", (int)difference); diffFromPrevious = (difference >= 30 * (ONE_G / 10)); } else { notFirstTime = true; diffFromPrevious = false; } bool pastBack = false; bool pastFwd = false; if (past[0] + past[1] + past[2] >= 1) { pastFwd = true; } else if (past[0] + past[1] + past[2] <= -1) { pastBack = true; } past[0] = past[1]; past[1] = past[2]; past[2] = now; bool wasMoving = !bayesStandingMode; #if 0 PRINTF("SSD \t%d\n", (int)(s >= THRESH_LOW)); PRINTF("MSD \t%d\n", (int)(s >= THRESH_MEDIUM)); PRINTF("LSD \t%d\n" , (int)(s > THRESH_HIGH)); PRINTF("Accelerating\t%d\n", (int)(nowFwd)); PRINTF("PastAccel \t%d\n", (int)(pastFwd)); PRINTF("PastBrake \t%d\n", (int)(pastBack)); PRINTF("WasMoving \t%d\n", (int)(wasMoving)); PRINTF("Diff \t%d\n", (int)(diffFromPrevious)); #endif calcNewProb(s, wasMoving, pastBack, pastFwd, nowFwd, diffFromPrevious); }
static inline void vnormal(float *v) { vscale(v,1.0/vlength(v)); }
f32 vdistance( const triple* x, const triple* y ){ triple v = *y; vsub( &v, x ); return vlength( &v ); }
void vnormal(float *v) { vscale(v,1.0/vlength(v)); }
/* normalise a vector */ void vnormal(double *v){ vscale(v, 1.0 / vlength(v)); }
bool arcball_event(struct Arcball* arcball, SDL_Event event) { static int32_t mouse_down = 0; static const float rotation_slowness_factor = 0.25f; static int32_t next_flipped = 0; // - arcball rotation is performed by dragging the mouse, so I just keep track of when // a mouse button is pressed and released between calls to this function by setting a // static variable mouse_down to the button number when a button is pressed and back // to 0 when that button is released if( event.type == SDL_MOUSEBUTTONDOWN && mouse_down == 0 ) { mouse_down = event.button.button; } else if( event.type == SDL_MOUSEBUTTONUP && mouse_down == event.button.button ) { arcball->flipped = next_flipped; mouse_down = 0; } if( mouse_down == arcball->translate_button && event.type == SDL_MOUSEMOTION ) { SDL_MouseMotionEvent mouse = event.motion; float eye_distance = arcball->camera.pivot.eye_distance; // - when an mouse motion event occurs, and mouse_down to the translation_button so we compute // a camera translation // - the camera should pan around on the x-z-plane, keeping its height and orientation Quat inverted_orientation = {0}; quat_invert(arcball->camera.pivot.orientation, inverted_orientation); // - the sideways translation is computed by taking the right_axis and orienting it with // the cameras orientation, the way I set up the lookat implementation this should always // result in a vector parallel to the x-z-plane Vec4f right_axis = RIGHT_AXIS; vec_rotate4f(right_axis, inverted_orientation, right_axis); if( mouse.xrel != 0 ) { // - then we'll just multiply the resulting axis with the mouse x relative movement, inversely // scaled by how far we are away from what we are looking at (farer means faster, nearer // means slower), the translation_factor is just a value that felt good when this was implemented Vec4f x_translation = {0}; vec_mul1f(right_axis, (float)mouse.xrel/arcball->translate_factor*eye_distance, x_translation); // - finally just add the x_translation to the target and position so that the whole arcball moves vec_add(arcball->target, x_translation, arcball->target); vec_add(arcball->camera.pivot.position, x_translation, arcball->camera.pivot.position); } // - the z translation can't be done along the orientated forward axis because that would include // the camera pitch, here, same as above, we need an axis that is parallel to the x-z-plane Vec4f up_axis = UP_AXIS; if( mouse.yrel != 0 ) { // - luckily such an axis is easily computed from the crossproduct of the orientated right_axis and // the default up_axis, the result is an axis pointing in the direction of the cameras forward axis, // while still being parallel to the x-z-plane Vec4f forward_axis; vec_cross(right_axis, up_axis, forward_axis); // - same as above Vec4f z_translation; vec_mul1f(forward_axis, (float)mouse.yrel/arcball->translate_factor*eye_distance, z_translation); // - dito vec_add(arcball->target, z_translation, arcball->target); vec_add(arcball->camera.pivot.position, z_translation, arcball->camera.pivot.position); } } else if( mouse_down == arcball->rotate_button && event.type == SDL_MOUSEMOTION ) { SDL_MouseMotionEvent mouse = event.motion; // - above case was translation, this is an rotation occuring: mouse_down is equal to the // rotation_button and the event is a mouse motion // - the camera needs to rotate around the target while keeping its height, orientation and // without _any_ rolling // - we want only yaw and pitch movement // - yaw is easy, just use the fixed up_axis and create a rotation the rotates around it // by the mouse x relative movement (converted to radians) // - the flipped value indicates if the camera is flipped over, so we'll just use that to // change the sign of the yaw to make the mouse movement on the screen always correctly // relates to the movement of the rotation Vec4f up_axis = UP_AXIS; Quat yaw_rotation = {0}; quat_from_axis_angle(up_axis, arcball->flipped * PI/180 * mouse.xrel * rotation_slowness_factor, yaw_rotation); // - pitch is a little more involved, I need to compute the orientated right axis and use // that to compute the pitch_rotation Quat inverted_orientation = {0}; quat_invert(arcball->camera.pivot.orientation, inverted_orientation); Vec4f right_axis = RIGHT_AXIS; vec_rotate4f(right_axis, inverted_orientation, right_axis); Quat pitch_rotation = {0}; quat_from_axis_angle(right_axis, -PI/180 * mouse.yrel * rotation_slowness_factor, pitch_rotation); // - combine yaw and pitch into a single rotation Quat rotation = {0}; quat_mul(yaw_rotation, pitch_rotation, rotation); // - orbit is the position translated to the coordinate root // - the yaw and pitch rotation is applied to the orbit // - orbit is translated back and replaces the camera position Vec4f orbit = {0}; vec_sub(arcball->camera.pivot.position, arcball->target, orbit); vec_rotate4f(orbit, rotation, orbit); vec_add(arcball->target, orbit, arcball->camera.pivot.position); // - after updating the position we just call lookat to compute the new // orientation, and also set the flipped state next_flipped = pivot_lookat(&arcball->camera.pivot, arcball->target); } if( event.type == SDL_MOUSEWHEEL ) { SDL_MouseWheelEvent wheel = event.wheel; // - zooming when mouse wheel event happens float* eye_distance = &arcball->camera.pivot.eye_distance; if( (*eye_distance > arcball->camera.frustum.z_near || wheel.y < 0) && (*eye_distance < arcball->camera.frustum.z_far || wheel.y > 0)) { // - just going back and forth along the oriented forward axis, using wheel // y motion inversly scaled by the eye_distance, similar to what is done // for the translation above (farer == faster zoom, nearer == slower zoom) Quat inverted_orientation = {0}; quat_invert(arcball->camera.pivot.orientation, inverted_orientation); Vec4f forward_axis = FORWARD_AXIS; vec_rotate4f(forward_axis, inverted_orientation, forward_axis); Vec4f zoom = {0}; vec_mul1f(forward_axis, wheel.y/arcball->zoom_factor*(*eye_distance), zoom); vec_add(arcball->camera.pivot.position, zoom, arcball->camera.pivot.position); // - eye_distance is kept in camera state, so we need to update it here *eye_distance = vlength(arcball->camera.pivot.position); } } return true; }
static void trackcsv(FILE *fo, const int trackno, byte *trk, long trklen, const int ppq) { int levt = 0, evt, channel, note, vel, control, value, type; vlint len; byte *titem; vlint abstime = 0; /* Absolute time in track */ #ifdef XDD byte *strk = trk; #endif while (trklen > 0) { vlint tlapse = vlength(&trk, &trklen); abstime += tlapse; fprintf(fo, "%d, %ld, ", trackno, abstime); /* Handle running status; if the next byte is a data byte, reuse the last command seen in the track. */ if (*trk & 0x80) { #ifdef XDD fprintf(fo, " (Trk: %02x NS: %02X : %d) ", *trk, evt, trk - strk); #endif evt = *trk++; /* One subtlety: we only save channel voice messages for running status. System messages and file meta-events (all of which are in the 0xF0-0xFF range) are not saved, as it is possible to carry a running status across them. You may have never seen this done in a MIDI file, but I have. */ if ((evt & 0xF0) != 0xF0) { levt = evt; } trklen--; } else { evt = levt; #ifdef XDD fprintf(fo, " (Trk: %02x RS: %02X : %d) ", *trk, evt, trk - strk); #endif } channel = evt & 0xF; /* Channel messages */ switch (evt & 0xF0) { case NoteOff: /* Note off */ if (trklen < 2) { return; } trklen -= 2; note = *trk++; vel = *trk++; fprintf(fo, "Note_off_c, %d, %d, %d\n", channel, note, vel); continue; case NoteOn: /* Note on */ if (trklen < 2) { return; } trklen -= 2; note = *trk++; vel = *trk++; /* A note on with a velocity of 0 is actually a note off. We do not translate it to a Note_off record in order to preserve the original structure of the MIDI file. */ fprintf(fo, "Note_on_c, %d, %d, %d\n", channel, note, vel); continue; case PolyphonicKeyPressure: /* Aftertouch */ if (trklen < 2) { return; } trklen -= 2; note = *trk++; vel = *trk++; fprintf(fo, "Poly_aftertouch_c, %d, %d, %d\n", channel, note, vel); continue; case ControlChange: /* Control change */ if (trklen < 2) { return; } trklen -= 2; control = *trk++; value = *trk++; fprintf(fo, "Control_c, %d, %d, %d\n", channel, control, value); continue; case ProgramChange: /* Program change */ if (trklen < 1) { return; } trklen--; note = *trk++; fprintf(fo, "Program_c, %d, %d\n", channel, note); continue; case ChannelPressure: /* Channel pressure (aftertouch) */ if (trklen < 1) { return; } trklen--; vel = *trk++; fprintf(fo, "Channel_aftertouch_c, %d, %d\n", channel, vel); continue; case PitchBend: /* Pitch bend */ if (trklen < 1) { return; } trklen--; value = *trk++; value = value | ((*trk++) << 7); fprintf(fo, "Pitch_bend_c, %d, %d\n", channel, value); continue; default: break; } switch (evt) { /* System exclusive messages */ case SystemExclusive: case SystemExclusivePacket: len = vlength(&trk, &trklen); fprintf(fo, "System_exclusive%s, %lu", evt == SystemExclusivePacket ? "_packet" : "", len); { vlint i; for (i = 0; i < len; i++) { fprintf(fo, ", %d", *trk++); } fprintf(fo, "\n"); } break; /* File meta-events */ case FileMetaEvent: if (trklen < 2) { return; } trklen -= 2; type = *trk++; len = vlength(&trk, &trklen); titem = trk; trk += len; trklen -= len; switch (type) { case SequenceNumberMetaEvent: fprintf(fo, "Sequence_number, %d\n", (titem[0] << 8) | titem[1]); break; case TextMetaEvent: #ifdef XDD fprintf(fo, " (Len=%ld Trk=%02x) ", len, *trk); #endif fputs("Text_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case CopyrightMetaEvent: fputs("Copyright_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case TrackTitleMetaEvent: fputs("Title_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case TrackInstrumentNameMetaEvent: fputs("Instrument_name_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case LyricMetaEvent: fputs("Lyric_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case MarkerMetaEvent: fputs("Marker_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case CuePointMetaEvent: fputs("Cue_point_t, ", fo); textcsv(fo, titem, len); putc('\n', fo); break; case ChannelPrefixMetaEvent: fprintf(fo, "Channel_prefix, %d\n", titem[0]); break; case PortMetaEvent: fprintf(fo, "MIDI_port, %d\n", titem[0]); break; case EndTrackMetaEvent: fprintf(fo, "End_track\n"); trklen = -1; break; case SetTempoMetaEvent: fprintf(fo, "Tempo, %d\n", (titem[0] << 16) | (titem[1] << 8) | titem[2]); break; case SMPTEOffsetMetaEvent: fprintf(fo, "SMPTE_offset, %d, %d, %d, %d, %d\n", titem[0], titem[1], titem[2], titem[3], titem[4]); break; case TimeSignatureMetaEvent: fprintf(fo, "Time_signature, %d, %d, %d, %d\n", titem[0], titem[1], titem[2], titem[3]); break; case KeySignatureMetaEvent: fprintf(fo, "Key_signature, %d, \"%s\"\n", ((signed char) titem[0]), titem[1] ? "minor" : "major"); break; case SequencerSpecificMetaEvent: fprintf(fo, "Sequencer_specific, %lu", len); { vlint i; for (i = 0; i < len; i++) { fprintf(fo, ", %d", titem[i]); } fprintf(fo, "\n"); } break; default: if (verbose) { fprintf(stderr, "Unknown meta event type 0x%02X, %ld bytes of data.\n", type, len); } fprintf(fo, "Unknown_meta_event, %d, %lu", type, len); { vlint i; for (i = 0; i < len; i++) { fprintf(fo, ", %d", titem[i]); } fprintf(fo, "\n"); } break; } break; default: if (verbose) { fprintf(stderr, "Unknown event type 0x%02X.\n", evt); } fprintf(fo, "Unknown_event, %02Xx\n", evt); break; } } }
static void normalize(float vector[3]) { float invlength = 1 / vlength(vector); vector[0] *= invlength; vector[1] *= invlength; vector[2] *= invlength; }