From: Burkhard P. <pl...@ip...> - 2005-03-08 12:28:41
|
> Yep, totally agree, please clearify the 'quiet' stuff a bit more btw :) It is set to 1 if the loudness dropped to analog silence during the last processed samples. For subsequent silent frames, it's set to 0. > I am currently writing the proposal for the VisAudio rewrite, I will > post that later in the evening. Please take a look at it :) Did so, see other message. > Depends, we want to provide good detection, but of course some plugins > will have need for something very specific that isn't in the library. > > We try to implement generalized things in the lib. Ok, this is what I have now: time_buffer_read contains the pcm sampes, after the call, e->loudness, e->beat_detected and e->quiet are updated. (e is the lemuria engine which holds all data belonging to one lemuria instance). It's a copy and paste from an onld blursk version and I didn't bother yet to improve this. #define BEAT_MAX 200 /* Config values from bursk */ #define BEAT_SENSITIVITY 4 typedef struct { int32_t beathistory[BEAT_MAX]; int beatbase; int32_t aged; /* smoothed out loudness */ int32_t lowest; /* quietest point in current beat */ int elapsed; /* frames since last beat */ int isquiet; /* was previous frame quiet */ int prevbeat; /* period of previous beat */ } lemuria_analysis; static int detect_beat(lemuria_analysis * a, int32_t loudness, int *thickref, int *quietref) { int beat, i, j; int32_t total; int sensitivity; /* Incorporate the current loudness into history */ a->aged = (a->aged * 7 + loudness) >> 3; a->elapsed++; /* If silent, then clobber the beat */ if (a->aged < 2000 || a->elapsed > BEAT_MAX) { a->elapsed = 0; a->lowest = a->aged; memset(a->beathistory, 0, sizeof a->beathistory); } else if (a->aged < a->lowest) a->lowest = a->aged; /* Beats are detected by looking for a sudden loudness after a lull. * They are also limited to occur no more than once every 15 frames, * so the beat flashes don't get too annoying. */ j = (a->beatbase + a->elapsed) % BEAT_MAX; a->beathistory[j] = loudness - a->aged; beat = FALSE; if (a->elapsed > 15 && a->aged > 2000 && loudness * 4 > a->aged * 5) { /* Compute the average loudness change, assuming this is beat */ for (i = BEAT_MAX / a->elapsed, total = 0; --i > 0; j = (j + BEAT_MAX - a->elapsed) % BEAT_MAX) { total += a->beathistory[j]; } total = total * a->elapsed / BEAT_MAX; /* Tweak the sensitivity to emphasize a consistent rhythm */ sensitivity = BEAT_SENSITIVITY; i = 3 - abs(a->elapsed - a->prevbeat)/2; if (i > 0) sensitivity += i; /* If average change is significantly positive, this is a beat. */ if (total * sensitivity > a->aged) { a->prevbeat = a->elapsed; a->beatbase = (a->beatbase + a->elapsed) % BEAT_MAX; a->lowest = a->aged; a->elapsed = 0; beat = TRUE; } } /* Thickness is computed from the difference between the instantaneous * loudness and the a->aged loudness. Thus, a sudden increase in volume * will produce a thick line, regardless of rhythm. */ if (a->aged < 1500) *thickref = 0; else { *thickref = loudness * 2 / a->aged; if (*thickref > 3) *thickref = 3; } /* Silence is computed from the a->aged loudness. The quietref value is * set to TRUE only at the start of silence, not throughout the silent * period. Also, there is some hysteresis so that silence followed * by a slight noise and more silence won't count as two silent * periods -- that sort of thing happens during many fade edits, so * we have to account for it. */ if (a->aged < (a->isquiet ? 1500 : 500)) { /* Quiet now -- is this the start of quiet? */ *quietref = !a->isquiet; a->isquiet = TRUE; } else { *quietref = FALSE; a->isquiet = FALSE; } /* return the result */ return beat; } void lemuria_analysis_perform(lemuria_engine_t * e) { int i, imin, imax, start; int32_t delta_sum; lemuria_analysis * a = (lemuria_analysis*)e->analysis; /* Find the maximum and minimum, with the restriction that * the minimum must occur after the maximum. */ for (i = 1, imin = imax = 0, delta_sum = 0; i < 127 / 2; i++) { if (e->time_buffer_read[0][i] < e->time_buffer_read[0][imin]) imin = i; if (e->time_buffer_read[0][i] > e->time_buffer_read[0][imax]) imin = imax = i; delta_sum += abs(e->time_buffer_read[0][i] - e->time_buffer_read[0][i - i]); } /* Triggered sweeps start halfway between min & max */ start = (imax + imin) / 2; /* Compute the loudness. We don't want to do a full spectrum analysis * to do this, but we can guess the low-frequency sound is proportional * to the maximum difference found (because loud low frequencies need * big signal changes), and that high-frequency sound is proportional * to the differences between adjacent samples. We want to be sensitive * to both of those, while ignoring the mid-range sound. * * Because we have only one low-frequency difference, but hundreds of * high-frequency differences, we need to give more weight to the * low-frequency difference (even though each high-frequency difference * is small). */ e->loudness = (((int32_t)e->time_buffer_read[0][imax] - (int32_t)e->time_buffer_read[0][imin]) * 60 + delta_sum) / 75; e->beat_detected = detect_beat(a, e->loudness, &(e->thickness), &(e->quiet)); } -- _____________________________ Dr.-Ing. Burkhard Plaum Institut fuer Plasmaforschung Pfaffenwaldring 31 70569 Stuttgart Tel.: +49 711 685-2187 Fax.: -3102 |