void aubio_beattracking_do (aubio_beattracking_t * bt, const fvec_t * dfframe, fvec_t * output) { uint_t i, k; uint_t step = bt->step; uint_t laglen = bt->rwv->length; uint_t winlen = bt->dfwv->length; uint_t maxindex = 0; //number of harmonics in shift invariant comb filterbank uint_t numelem = 4; smpl_t phase; // beat alignment (step - lastbeat) smpl_t beat; // beat position smpl_t bp; // beat period uint_t a, b; // used to build shift invariant comb filterbank uint_t kmax; // number of elements used to find beat phase /* copy dfframe, apply detection function weighting, and revert */ fvec_copy (dfframe, bt->dfrev); fvec_weight (bt->dfrev, bt->dfwv); fvec_rev (bt->dfrev); /* compute autocorrelation function */ aubio_autocorr (dfframe, bt->acf); /* if timesig is unknown, use metrically unbiased version of filterbank */ if (!bt->timesig) { numelem = 4; } else { numelem = bt->timesig; } /* first and last output values are left intentionally as zero */ fvec_zeros (bt->acfout); /* compute shift invariant comb filterbank */ for (i = 1; i < laglen - 1; i++) { for (a = 1; a <= numelem; a++) { for (b = 1; b < 2 * a; b++) { bt->acfout->data[i] += bt->acf->data[i * a + b - 1] * 1. / (2. * a - 1.); } } } /* apply Rayleigh weight */ fvec_weight (bt->acfout, bt->rwv); /* find non-zero Rayleigh period */ maxindex = fvec_max_elem (bt->acfout); if (maxindex > 0 && maxindex < bt->acfout->length - 1) { bt->rp = fvec_quadratic_peak_pos (bt->acfout, maxindex); } else { bt->rp = bt->rayparam; } /* activate biased filterbank */ aubio_beattracking_checkstate (bt); #if 0 // debug metronome mode bt->bp = 36.9142; #endif bp = bt->bp; /* end of biased filterbank */ if (bp == 0) { fvec_zeros(output); return; } /* deliberate integer operation, could be set to 3 max eventually */ kmax = FLOOR (winlen / bp); /* initialize output */ fvec_zeros (bt->phout); for (i = 0; i < bp; i++) { for (k = 0; k < kmax; k++) { bt->phout->data[i] += bt->dfrev->data[i + (uint_t) ROUND (bp * k)]; } } fvec_weight (bt->phout, bt->phwv); /* find Rayleigh period */ maxindex = fvec_max_elem (bt->phout); if (maxindex >= winlen - 1) { #if AUBIO_BEAT_WARNINGS AUBIO_WRN ("no idea what this groove's phase is\n"); #endif /* AUBIO_BEAT_WARNINGS */ phase = step - bt->lastbeat; } else { phase = fvec_quadratic_peak_pos (bt->phout, maxindex); } /* take back one frame delay */ phase += 1.; #if 0 // debug metronome mode phase = step - bt->lastbeat; #endif /* reset output */ fvec_zeros (output); i = 1; beat = bp - phase; // AUBIO_DBG ("bp: %f, phase: %f, lastbeat: %f, step: %d, winlen: %d\n", // bp, phase, bt->lastbeat, step, winlen); /* the next beat will be earlier than 60% of the tempo period skip this one */ if ( ( step - bt->lastbeat - phase ) < -0.40 * bp ) { #if AUBIO_BEAT_WARNINGS AUBIO_WRN ("back off-beat error, skipping this beat\n"); #endif /* AUBIO_BEAT_WARNINGS */ beat += bp; } /* start counting the beats */ while (beat + bp < 0) { beat += bp; } if (beat >= 0) { //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat); output->data[i] = beat; i++; } while (beat + bp <= step) { beat += bp; //AUBIO_DBG ("beat: %d, %f, %f\n", i, bp, beat); output->data[i] = beat; i++; } bt->lastbeat = beat; /* store the number of beats in this frame as the first element */ output->data[0] = i; }
aubio_source_avcodec_t * new_aubio_source_avcodec(char_t * path, uint_t samplerate, uint_t hop_size) { aubio_source_avcodec_t * s = AUBIO_NEW(aubio_source_avcodec_t); int err; if (path == NULL) { AUBIO_ERR("Aborted opening null path\n"); goto beach; } if ((sint_t)samplerate < 0) { AUBIO_ERR("Can not open %s with samplerate %d\n", path, samplerate); goto beach; } if ((sint_t)hop_size <= 0) { AUBIO_ERR("Can not open %s with hop_size %d\n", path, hop_size); goto beach; } s->hop_size = hop_size; s->channels = 1; s->path = path; // register all formats and codecs av_register_all(); // if path[0] != '/' //avformat_network_init(); // try opening the file and get some info about it AVFormatContext *avFormatCtx = s->avFormatCtx; avFormatCtx = NULL; if ( (err = avformat_open_input(&avFormatCtx, s->path, NULL, NULL) ) < 0 ) { char errorstr[256]; av_strerror (err, errorstr, sizeof(errorstr)); AUBIO_ERR("Failed opening %s (%s)\n", s->path, errorstr); goto beach; } // try to make sure max_analyze_duration is big enough for most songs avFormatCtx->max_analyze_duration *= 100; // retrieve stream information if ( (err = avformat_find_stream_info(avFormatCtx, NULL)) < 0 ) { char errorstr[256]; av_strerror (err, errorstr, sizeof(errorstr)); AUBIO_ERR("Could not find stream information " "for %s (%s)\n", s->path, errorstr); goto beach; } // dump information about file onto standard error //av_dump_format(avFormatCtx, 0, s->path, 0); // look for the first audio stream uint_t i; sint_t selected_stream = -1; for (i = 0; i < avFormatCtx->nb_streams; i++) { if (avFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if (selected_stream == -1) { selected_stream = i; } else { AUBIO_WRN("More than one audio stream in %s, " "taking the first one\n", s->path); } } } if (selected_stream == -1) { AUBIO_ERR("No audio stream in %s\n", s->path); goto beach; } //AUBIO_DBG("Taking stream %d in file %s\n", selected_stream, s->path); s->selected_stream = selected_stream; AVCodecContext *avCodecCtx = s->avCodecCtx; avCodecCtx = avFormatCtx->streams[selected_stream]->codec; AVCodec *codec = avcodec_find_decoder(avCodecCtx->codec_id); if (codec == NULL) { AUBIO_ERR("Could not find decoder for %s", s->path); goto beach; } if ( ( err = avcodec_open2(avCodecCtx, codec, NULL) ) < 0) { char errorstr[256]; av_strerror (err, errorstr, sizeof(errorstr)); AUBIO_ERR("Could not load codec for %s (%s)\n", s->path, errorstr); goto beach; } /* get input specs */ s->input_samplerate = avCodecCtx->sample_rate; s->input_channels = avCodecCtx->channels; //AUBIO_DBG("input_samplerate: %d\n", s->input_samplerate); //AUBIO_DBG("input_channels: %d\n", s->input_channels); if (samplerate == 0) { samplerate = s->input_samplerate; //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate); } s->samplerate = samplerate; if (s->samplerate > s->input_samplerate) { AUBIO_WRN("upsampling %s from %d to %d\n", s->path, s->input_samplerate, s->samplerate); } AVFrame *avFrame = s->avFrame; avFrame = avcodec_alloc_frame(); if (!avFrame) { AUBIO_ERR("Could not allocate frame for (%s)\n", s->path); } /* allocate output for avr */ s->output = (float *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE * sizeof(float)); s->read_samples = 0; s->read_index = 0; s->avFormatCtx = avFormatCtx; s->avCodecCtx = avCodecCtx; s->avFrame = avFrame; // default to mono output aubio_source_avcodec_reset_resampler(s, 0); s->eof = 0; s->multi = 0; //av_log_set_level(AV_LOG_QUIET); return s; beach: //AUBIO_ERR("can not read %s at samplerate %dHz with a hop_size of %d\n", // s->path, s->samplerate, s->hop_size); del_aubio_source_avcodec(s); return NULL; }
void aubio_beattracking_checkstate (aubio_beattracking_t * bt) { uint_t i, j, a, b; uint_t flagconst = 0; sint_t counter = bt->counter; uint_t flagstep = bt->flagstep; smpl_t gp = bt->gp; smpl_t bp = bt->bp; smpl_t rp = bt->rp; smpl_t rp1 = bt->rp1; smpl_t rp2 = bt->rp2; uint_t laglen = bt->rwv->length; uint_t acflen = bt->acf->length; uint_t step = bt->step; fvec_t *acf = bt->acf; fvec_t *acfout = bt->acfout; if (gp) { // compute shift invariant comb filterbank fvec_zeros (acfout); for (i = 1; i < laglen - 1; i++) { for (a = 1; a <= bt->timesig; a++) { for (b = 1; b < 2 * a; b++) { acfout->data[i] += acf->data[i * a + b - 1]; } } } // since gp is set, gwv has been computed in previous checkstate fvec_weight (acfout, bt->gwv); gp = fvec_quadratic_peak_pos (acfout, fvec_max_elem (acfout)); } else { //still only using general model gp = 0; } //now look for step change - i.e. a difference between gp and rp that // is greater than 2*constthresh - always true in first case, since gp = 0 if (counter == 0) { if (ABS (gp - rp) > 2. * bt->g_var) { flagstep = 1; // have observed step change. counter = 3; // setup 3 frame counter } else { flagstep = 0; } } //i.e. 3rd frame after flagstep initially set if (counter == 1 && flagstep == 1) { //check for consistency between previous beatperiod values if (ABS (2 * rp - rp1 - rp2) < bt->g_var) { //if true, can activate context dependent model flagconst = 1; counter = 0; // reset counter and flagstep } else { //if not consistent, then don't flag consistency! flagconst = 0; counter = 2; // let it look next time } } else if (counter > 0) { //if counter doesn't = 1, counter = counter - 1; } rp2 = rp1; rp1 = rp; if (flagconst) { /* first run of new hypothesis */ gp = rp; bt->timesig = fvec_gettimesig (acf, acflen, gp); for (j = 0; j < laglen; j++) bt->gwv->data[j] = EXP (-.5 * SQR ((smpl_t) (j + 1. - gp)) / SQR (bt->g_var)); flagconst = 0; bp = gp; /* flat phase weighting */ fvec_ones (bt->phwv); } else if (bt->timesig) { /* context dependant model */ bp = gp; /* gaussian phase weighting */ if (step > bt->lastbeat) { for (j = 0; j < 2 * laglen; j++) { bt->phwv->data[j] = EXP (-.5 * SQR ((smpl_t) (1. + j - step + bt->lastbeat)) / (bp / 8.)); } } else { //AUBIO_DBG("NOT using phase weighting as step is %d and lastbeat %d \n", // step,bt->lastbeat); fvec_ones (bt->phwv); } } else { /* initial state */ bp = rp; /* flat phase weighting */ fvec_ones (bt->phwv); } /* do some further checks on the final bp value */ /* if tempo is > 206 bpm, half it */ while (0 < bp && bp < 25) { #if AUBIO_BEAT_WARNINGS AUBIO_WRN ("doubling from %f (%f bpm) to %f (%f bpm)\n", bp, 60.*44100./512./bp, bp/2., 60.*44100./512./bp/2. ); //AUBIO_DBG("warning, halving the tempo from %f\n", 60.*samplerate/hopsize/bp); #endif /* AUBIO_BEAT_WARNINGS */ bp = bp * 2; } //AUBIO_DBG("tempo:\t%3.5f bpm | ", 5168./bp); /* smoothing */ //bp = (uint_t) (0.8 * (smpl_t)bp + 0.2 * (smpl_t)bp2); //AUBIO_DBG("tempo:\t%3.5f bpm smoothed | bp2 %d | bp %d | ", 5168./bp, bp2, bp); //bp2 = bp; //AUBIO_DBG("time signature: %d \n", bt->timesig); bt->counter = counter; bt->flagstep = flagstep; bt->gp = gp; bt->bp = bp; bt->rp1 = rp1; bt->rp2 = rp2; }
int aubio_audio_unit_blocking(aubio_audio_unit_t *o) { uint_t sw_output_channels, sw_input_channels, hw_output_channels, hw_input_channels, i, j, blocksize; if (! o->callback) return -1; smpl_t ** tbuf; sw_output_channels = o->sw_output_channels; sw_input_channels = o->sw_input_channels; hw_output_channels = o->hw_output_channels; hw_input_channels = o->hw_input_channels; blocksize = o->blocksize; if (!sw_input_channels && !sw_output_channels) goto fail; if (o->dio_error) { AUBIO_WRN("audio_unit: dio error %d\n", o->total_frames); o->dio_error = 0; } if (o->au_ios_inbuf) { /* copy samples from input buffer */ tbuf = o->input_frames->data; if (o->input_enabled) { for (j = 0; j < blocksize;j++) { for (i = 0; i < sw_input_channels && i < hw_input_channels; i++) { //tbuf[i][j] = // (smpl_t)(o->au_ios_inbuf[i + (j + o->au_ios_end) * sw_input_channels] / 32768.); // on iphone, input is mono, copy right to left channel tbuf[i][j] = (smpl_t) o->au_ios_inbuf[0 + (j + o->au_ios_end) * hw_input_channels] * INT_TO_FLOAT; } } } else { // input is disabled, fill with zeroes for (j = 0; j < blocksize; j++) { for (i = 0; i < sw_input_channels && i < hw_input_channels; i++) { tbuf[i][j] = 0; } } } } o->callback(o->callback_closure, o->input_frames, o->output_frames); /* copy samples to output buffer */ tbuf = o->output_frames->data; for (i = 0; i < o->output_frames->height; i++) { for (j = 0; j < o->output_frames->length; j++) { smpl_t val = tbuf[i][j]; if (val < -1.0) val = -1.0; if (val > 1.0) val = 1.0; o->au_ios_outbuf[i + (j + o->au_ios_end) * hw_output_channels ] = (SInt16)(val * 32767); } } o->au_ios_end += blocksize; o->au_ios_end %= AU_IOS_MAX_FRAMES; o->total_frames += blocksize; return 0; fail: AUBIO_ERR("audio_unit: callback() failed\n"); o->total_frames += AU_IOS_MAX_FRAMES; return 1; }
aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t samplerate, uint_t block_size) { aubio_source_apple_audio_t * s = AUBIO_NEW(aubio_source_apple_audio_t); s->path = path; s->block_size = block_size; OSStatus err = noErr; UInt32 propSize; // open the resource url CFURLRef fileURL = getURLFromPath(path); err = ExtAudioFileOpenURL(fileURL, &s->audioFile); if (err) { AUBIO_ERR("error when trying to access %s, in ExtAudioFileOpenURL, %d\n", s->path, (int)err); goto beach;} // create an empty AudioStreamBasicDescription AudioStreamBasicDescription fileFormat; propSize = sizeof(fileFormat); memset(&fileFormat, 0, sizeof(AudioStreamBasicDescription)); // fill it with the file description err = ExtAudioFileGetProperty(s->audioFile, kExtAudioFileProperty_FileDataFormat, &propSize, &fileFormat); if (err) { AUBIO_ERROR("error in ExtAudioFileGetProperty, %d\n", (int)err); goto beach;} if (samplerate == 0) { samplerate = fileFormat.mSampleRate; //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate); } s->samplerate = samplerate; s->source_samplerate = fileFormat.mSampleRate; s->channels = fileFormat.mChannelsPerFrame; AudioStreamBasicDescription clientFormat; propSize = sizeof(clientFormat); memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription)); clientFormat.mFormatID = kAudioFormatLinearPCM; clientFormat.mSampleRate = (Float64)(s->samplerate); clientFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; clientFormat.mChannelsPerFrame = s->channels; clientFormat.mBitsPerChannel = sizeof(short) * 8; clientFormat.mFramesPerPacket = 1; clientFormat.mBytesPerFrame = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8; clientFormat.mBytesPerPacket = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame; clientFormat.mReserved = 0; // set the client format description err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat, propSize, &clientFormat); if (err) { AUBIO_ERROR("error in ExtAudioFileSetProperty, %d\n", (int)err); #if 1 // print client and format descriptions AUBIO_DBG("Opened %s\n", s->path); AUBIO_DBG("file/client Format.mFormatID: : %3c%c%c%c / %c%c%c%c\n", (int)RT_BYTE4(fileFormat.mFormatID), (int)RT_BYTE3(fileFormat.mFormatID), (int)RT_BYTE2(fileFormat.mFormatID), (int)RT_BYTE1(fileFormat.mFormatID), (int)RT_BYTE4(clientFormat.mFormatID), (int)RT_BYTE3(clientFormat.mFormatID), (int)RT_BYTE2(clientFormat.mFormatID), (int)RT_BYTE1(clientFormat.mFormatID) ); AUBIO_DBG("file/client Format.mSampleRate : %6.0f / %.0f\n", fileFormat.mSampleRate , clientFormat.mSampleRate); AUBIO_DBG("file/client Format.mFormatFlags : %6d / %d\n", (int)fileFormat.mFormatFlags , (int)clientFormat.mFormatFlags); AUBIO_DBG("file/client Format.mChannelsPerFrame : %6d / %d\n", (int)fileFormat.mChannelsPerFrame, (int)clientFormat.mChannelsPerFrame); AUBIO_DBG("file/client Format.mBitsPerChannel : %6d / %d\n", (int)fileFormat.mBitsPerChannel , (int)clientFormat.mBitsPerChannel); AUBIO_DBG("file/client Format.mFramesPerPacket : %6d / %d\n", (int)fileFormat.mFramesPerPacket , (int)clientFormat.mFramesPerPacket); AUBIO_DBG("file/client Format.mBytesPerFrame : %6d / %d\n", (int)fileFormat.mBytesPerFrame , (int)clientFormat.mBytesPerFrame); AUBIO_DBG("file/client Format.mBytesPerPacket : %6d / %d\n", (int)fileFormat.mBytesPerPacket , (int)clientFormat.mBytesPerPacket); AUBIO_DBG("file/client Format.mReserved : %6d / %d\n", (int)fileFormat.mReserved , (int)clientFormat.mReserved); #endif goto beach; } // compute the size of the segments needed to read the input file UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame; Float64 rateRatio = clientFormat.mSampleRate / fileFormat.mSampleRate; uint_t segmentSize= (uint_t)(samples * rateRatio + .5); if (rateRatio < 1.) { segmentSize = (uint_t)(samples / rateRatio + .5); } else if (rateRatio > 1.) { AUBIO_WRN("up-sampling %s from %0.2fHz to %0.2fHz\n", s->path, fileFormat.mSampleRate, clientFormat.mSampleRate); } else { assert ( segmentSize == samples ); //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size); } // allocate the AudioBufferList if (createAubioBufferList(&s->bufferList, s->channels, segmentSize)) err = -1; return s; beach: AUBIO_FREE(s); return NULL; }