From patchwork Thu Jun 25 15:45:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ashutosh Pradhan X-Patchwork-Id: 20605 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 7114D449A96 for ; Thu, 25 Jun 2020 19:14:34 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 473B7688060; Thu, 25 Jun 2020 19:14:34 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-il1-f172.google.com (mail-il1-f172.google.com [209.85.166.172]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EE652680379 for ; Thu, 25 Jun 2020 19:14:26 +0300 (EEST) Received: by mail-il1-f172.google.com with SMTP id t27so883537ill.9 for ; Thu, 25 Jun 2020 09:14:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=FNkFMPbPSKt3NZHIVTbY+z9pi9gp7O8c9C/ZO8J6caE=; b=pBhbQS+I3lociDG4Qs7X1u6FvLY77mELA86ndDtFvsXIgOw8IsrZ2fsCcCL6tVc6GI mEGvijjfk9zLnbPFFpJ19lYwOu5K4om0d4GZuWp3ZGnHvXC3f9hNTgdP1ox7YD3bb75e 4gokKulgZa/2kC5St68Nt/kIb4hE6zr+J3AkOGUN68lEmRdIIDEYkEoZG66q9HZ05nGy 8UNlr+YXph1HxRgPy2wtQ53zkwEiixPDb+yUTYitbFJyknDF7WjvhI1qoMH9LKX8sIZr Il5A2uE8rhjTLuXxdM85EwqAny/UKss2srnYX93rYoLIg32ksqr98cjyIdc1wtFlSOYI zeVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=FNkFMPbPSKt3NZHIVTbY+z9pi9gp7O8c9C/ZO8J6caE=; b=QbRTjAE+mUIc+MUY+2lfPsMYK4EOLWHkcpiiNmticxfG4PCeXfYtYVhBNOgsogpA9l Hp/23jkOyzLTbFYD9sS9lnR6JX+fsw29crBGoLGPut/cgcwg3iXKz2yU4C06s9Y5b4CW rstyruqH+Ua5Mj0DNXVLVQ5mpt8Ag7/4XQx+0MKCSRO1LQuL3VGTgtKHzu1QMTrcOtVF jT3NRtzk+l/rSqxLrLO6Zbm8tOr3NPQoQlo8CVtcZXut+YcO6tsHsmkno/RCMCLzVJHN 7jRaVoeUVh89TtAwL4gDw7OL0DwrjOrgiqe44/NTyeuqnMJ1P8yw5KZKukiuONGxnYrF KHjw== X-Gm-Message-State: AOAM532XO6KyoQY1a7vKDcaV7mW3RElk3Q+ivCebt+sxDTiCbtV8MWEU GmNK+GzG0ajySy0V3q4nv92e4e36bqc= X-Google-Smtp-Source: ABdhPJxMsb4cwAYw0OjgQ87fYFHdir4+CfJc0Y3MGy15uCjFImmQ2DJ0tAcm8Vf+gO8PH6HBD4hYFQ== X-Received: by 2002:a63:f408:: with SMTP id g8mr28059170pgi.184.1593099914577; Thu, 25 Jun 2020 08:45:14 -0700 (PDT) Received: from localhost.localdomain ([223.233.35.238]) by smtp.gmail.com with ESMTPSA id v62sm12219802pfb.119.2020.06.25.08.45.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Jun 2020 08:45:13 -0700 (PDT) From: Ashutosh Pradhan To: ffmpeg-devel@ffmpeg.org Date: Thu, 25 Jun 2020 21:15:06 +0530 Message-Id: <20200625154506.16483-1-ashutoshp012345@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: Subject: [FFmpeg-devel] [PATCH]libavfilter/asrc_atone.c : generate algorithmic music X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: ashutoshp012345@gmail.com MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Generate algorithmic riff music. Changed to activate api. Changelog | 2 +- configure | 4 + doc/filters.texi | 56 ++++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/asrc_atone.c | 474 +++++++++++++++++++++++++++++++++++++++++++++++ libavfilter/notedef.h | 264 ++++++++++++++++++++++++++ libavfilter/version.h | 2 +- 8 files changed, 802 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index a60e7d2eb8..ec12027740 100644 --- a/Changelog +++ b/Changelog @@ -80,7 +80,7 @@ version 4.3: - PFM decoder - dblur video filter - Real War KVAG muxer - +- atone filter version 4.2: - tpad filter diff --git a/configure b/configure index 7495f35faa..825e38a4b0 100755 --- a/configure +++ b/configure @@ -233,6 +233,7 @@ External library support: and libraw1394 [no] --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] --enable-libflite enable flite (voice synthesis) support via libflite [no] + --enable-libfluidsynth enable libfluidsynth support for fluidsynth [no] --enable-libfontconfig enable libfontconfig, useful for drawtext filter [no] --enable-libfreetype enable libfreetype, needed for drawtext filter [no] --enable-libfribidi enable libfribidi, improves drawtext filter [no] @@ -1772,6 +1773,7 @@ EXTERNAL_LIBRARY_LIST=" libdc1394 libdrm libflite + libfluidsynth libfontconfig libfreetype libfribidi @@ -3486,6 +3488,7 @@ asr_filter_deps="pocketsphinx" ass_filter_deps="libass" atempo_filter_deps="avcodec" atempo_filter_select="rdft" +atone_filter_deps="libfluidsynth" avgblur_opencl_filter_deps="opencl" avgblur_vulkan_filter_deps="vulkan libglslang" azmq_filter_deps="libzmq" @@ -6307,6 +6310,7 @@ enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aace warn "using libfdk without pkg-config"; } } flite_extralibs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmulex -lflite" enabled libflite && require libflite "flite/flite.h" flite_init $flite_extralibs +enabled libfluidsynth && require_pkg_config libfluidsynth fluidsynth "fluidsynth.h" fluid_log enabled fontconfig && enable libfontconfig enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontconfig/fontconfig.h" FcInit enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType diff --git a/doc/filters.texi b/doc/filters.texi index 3c2dd2eb90..8733b52a2f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -6128,6 +6128,62 @@ anoisesrc=d=60:c=pink:r=44100:a=0.5 @end example @end itemize +@section atone + +Generate algorithmic riff music. +To compile filter configure ffmpeg with @code{--enable-libfluidsynth} + +The filter accepts the following options: + +@table @option +@item sample_rate, r +Specify the sample rate. Default value is 44100 Hz. + +@item sfont +Specify the location of soundfont file. Default value is +"/usr/share/sounds/sf2/FluidR3_GM.sf2"(for linux). + +@item duration, d +Specify the duration of the generated audio stream. Not specifying this option +results in playing tones for infinite length. + +@item velocity, v +Specify the velocity of key press. Default value is 80. + +@item percussion_velocity +Specify the velocity of key press for percussion track. Default value is 127. + +@item bpm +Specify the beats per minute. Default is 100. + +@item instrument +Specify the instrument. Available instruments are Acoustic-Grand, +Bright-Acoustic, ... as defined in the General Midi specifications. Default is Trumpet. + +@item percussion +Specify the percussion track for beats. Available options are Jazz1, +Jazz2, ..., Jazz6, Rock1...4, Shuffle, Metronome. Default is Metronome. + +@item numbars +Set the number of bars in which riff energy will change between 0 to 8. Default is 2. + +@item samples_per_frame +Set the number of samples per each output frame. Default is 1024. +@end table + +@subsection Examples + +@itemize + +@item +Generate 10 seconds of riff music, with a key velocity of 100, instrument as Electric Guitar(jazz) +and percussion track as Jazz3: +@example +atone=d=10:v=100:sfont="example.sf2":instrument=Electric-Guitar-Jazz:percussion=Jazz3 +atone=duration=10:velocity=100:sfont="example.sf2":instrument=Electric-Guitar-Jazz:percussion=Jazz3 +@end example +@end itemize + @section hilbert Generate odd-tap Hilbert transform FIR coefficients. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 5123540653..b0938830f2 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -152,6 +152,7 @@ OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o +OBJS-$(CONFIG_ATONE_FILTER) += asrc_atone.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 1183e40267..90f266a2d9 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -146,6 +146,7 @@ extern AVFilter ff_asrc_flite; extern AVFilter ff_asrc_hilbert; extern AVFilter ff_asrc_sinc; extern AVFilter ff_asrc_sine; +extern AVFilter ff_asrc_atone; extern AVFilter ff_asink_anullsink; diff --git a/libavfilter/asrc_atone.c b/libavfilter/asrc_atone.c new file mode 100644 index 0000000000..f018732017 --- /dev/null +++ b/libavfilter/asrc_atone.c @@ -0,0 +1,474 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/eval.h" +#include "libavutil/opt.h" +#include "libavutil/lfg.h" +#include "libavutil/random_seed.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" +#include "notedef.h" + +typedef struct AtoneContext +{ + const AVClass *class; + int64_t duration; + int nb_samples; + int sample_rate; + int64_t pts; + int infinite; + + fluid_settings_t *settings; + fluid_synth_t *synth; + fluid_sequencer_t *sequencer; + short synth_destination, client_destination; + unsigned int beat_dur; + unsigned int beats_pm; + unsigned int time_marker; + char *sfont; ///< soundfont file + int velocity; ///< velocity of key + int percussion_velocity; ///< velocity of key in percussion + double changerate; + + int *riffs; + int numriffs; + int last_note; + int framecount; + char *instrument; + percussion track; + char *track_name; + int numbars; + int64_t seed; + AVLFG r; + int i; +}AtoneContext; +#define CONTEXT AtoneContext +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +#define OPT_GENERIC(name, field, def, min, max, descr, type, deffield, ...) \ + { name, descr, offsetof(CONTEXT, field), AV_OPT_TYPE_ ## type, \ + { .deffield = def }, min, max, FLAGS, __VA_ARGS__ } + +#define OPT_INT(name, field, def, min, max, descr, ...) \ + OPT_GENERIC(name, field, def, min, max, descr, INT, i64, __VA_ARGS__) + +#define OPT_DBL(name, field, def, min, max, descr, ...) \ + OPT_GENERIC(name, field, def, min, max, descr, DOUBLE, dbl, __VA_ARGS__) + +#define OPT_DUR(name, field, def, min, max, descr, ...) \ + OPT_GENERIC(name, field, def, min, max, descr, DURATION, str, __VA_ARGS__) + +#define OPT_STR(name, field, def, min, max, descr, ...) \ + OPT_GENERIC(name, field, def, min, max, descr, STRING, str, __VA_ARGS__) + +static const AVOption atone_options[] = { + OPT_INT("velocity", velocity, 80, 0, 127, "set the velocity of key press",), + OPT_INT("v", velocity, 80, 0, 127, "set the velocity of key press",), + OPT_INT("percussion_velocity",percussion_velocity, 127, 0, 127, "set the velocity of key press",), + OPT_INT("sample_rate", sample_rate, 44100, 1, INT_MAX, "set the sample rate",), + OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate",), + OPT_DUR("duration", duration, 0, 0, INT64_MAX, "set the audio duration",), + OPT_DUR("d", duration, 0, 0, INT64_MAX, "set the audio duration",), + OPT_STR("sfont", sfont, "/usr/share/sounds/sf2/FluidR3_GM.sf2", 0, 0, "set the soundfont file",), + OPT_INT("samples_per_frame", nb_samples, 1024, 0, INT_MAX, "set the number of samples per frame",), + OPT_INT("bpm", beats_pm, 100, 0, INT_MAX, "set the beats per minute",), + OPT_STR("instrument", instrument, "Trumpet", 0, 0, "set the instrument",), + OPT_STR("percussion", track_name, "Metronome", 0, 0, "set the percussion track",), + OPT_INT("numbars", numbars, 2, 0, 8, "set the riff bars",), + {NULL} +}; + +AVFILTER_DEFINE_CLASS(atone); + +static void sequencer_callback(unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data); +static void instrument_select(int prog_no, unsigned int ticks, AtoneContext *s); +static int find_instrument(const char *instrument); +static int find_percussion_track(char *s); +static av_cold int init(AVFilterContext *ctx) +{ + AtoneContext *s = ctx->priv; + int sfont_id; + + /*Initialise the fluidsynth settings object followed by synthesizer*/ + s->settings = new_fluid_settings(); + if (s->settings == NULL) { + av_log(s, AV_LOG_ERROR, "Failed to create the fluidsynth settings"); + return AVERROR_EXTERNAL; + } + s->synth = new_fluid_synth(s->settings); + if (s->synth == NULL) { + av_log(s, AV_LOG_ERROR, "Failed to create the fluidsynth synth"); + return AVERROR_EXTERNAL; + } + sfont_id = fluid_synth_sfload(s->synth, s->sfont, 1); + if (sfont_id == FLUID_FAILED) { + av_log(s, AV_LOG_ERROR, "Loading the Soundfont Failed"); + return AVERROR_EXTERNAL; + } + if (!(s->riffs = av_malloc(sizeof(riff)))) + return AVERROR(ENOMEM); + + s->framecount=0; + s->sequencer = new_fluid_sequencer2(0); + /* register the synth with the sequencer */ + s->synth_destination = fluid_sequencer_register_fluidsynth(s->sequencer, s->synth); + /* register the client name and callback */ + s->client_destination = fluid_sequencer_register_client(s->sequencer, "atone", sequencer_callback, s); + s->time_marker = fluid_sequencer_get_tick(s->sequencer); + /*get the beat duration in TICKS 1 quarter note per beat*/ + s->beat_dur = 60000/s->beats_pm; + /*get change interval in frames/sec*/ + s->changerate = (4*s->beat_dur)*s->sample_rate/s->nb_samples; + if (s->changerate<1.0) + s->changerate = 1.0; + + s->last_note = 0; + s->numriffs = sizeof(riff)/(NPR* sizeof(int)); + s->seed = av_get_random_seed(); + av_lfg_init(&s->r, s->seed); + + for (int i = 0; i < s->numriffs*NPR ; i++) + s->riffs[i] = riff[i]; + + s->i = find_percussion_track(s->track_name); + instrument_select(find_instrument(s->instrument), s->time_marker, s); + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AtoneContext *s = ctx->priv; + + delete_fluid_sequencer(s->sequencer); + delete_fluid_synth(s->synth); + delete_fluid_settings(s->settings); + av_freep(&s->riffs); +} + +static av_cold int config_props(AVFilterLink *outlink) +{ + AtoneContext *s = outlink->src->priv; + + if (s->duration == 0) + s->infinite = 1; + + s->duration = av_rescale(s->duration, s->sample_rate, AV_TIME_BASE); + + if (s->framecount == INT_MAX) + s->framecount = 0; + + return 0; +} + +static int find_instrument(const char *instrument) +{ + for (int i = 0; i < sizeof(GM_instrument_list)/sizeof(GM_instrument_list[0]); i++) + if (strcmp(GM_instrument_list[i], instrument) == 0) + return i; + + return 0; +} + +static void instrument_select(int prog_no, unsigned int ticks, AtoneContext *s) +{ + fluid_event_t *ev = new_fluid_event(); + + fluid_event_set_source(ev, -1); + fluid_event_set_dest(ev,s->synth_destination); + fluid_event_program_change(ev, 0, prog_no); + fluid_sequencer_send_at(s->sequencer, ev, ticks, 1); + delete_fluid_event(ev); +} + +/* schedule a note on message */ +static void schedule_noteon(int chan, short key, unsigned int ticks, int velocity, AtoneContext *s) +{ + fluid_event_t *ev = new_fluid_event(); + + fluid_event_set_source(ev, -1); + fluid_event_set_dest(ev,s->synth_destination); + fluid_event_noteon(ev, chan, key, velocity); + fluid_sequencer_send_at(s->sequencer, ev, ticks, 1); + delete_fluid_event(ev); +} + +/* schedule a note off message */ +static void schedule_noteoff(int chan, short key, unsigned int ticks, AtoneContext *s) +{ + fluid_event_t *ev = new_fluid_event(); + + fluid_event_set_source(ev, -1); + fluid_event_set_dest(ev, s->synth_destination); + fluid_event_noteoff(ev, chan, key); + fluid_sequencer_send_at(s->sequencer, ev, ticks, 1); + delete_fluid_event(ev); +} + +/* schedule a timer event to trigger the callback */ +static void schedule_timer_event(AtoneContext *s) +{ + fluid_event_t *ev = new_fluid_event(); + + fluid_event_set_source(ev, -1); + fluid_event_set_dest(ev, s->client_destination); + fluid_event_timer(ev, NULL); + fluid_sequencer_send_at(s->sequencer, ev, s->time_marker, 1); + delete_fluid_event(ev); +} + +/*Determine the closest riff to the previous riff within three tries to make the transition between riffs smoother*/ +static int pick_riff(AtoneContext *s) +{ + int min, dn, riff, bestriff = 0; + unsigned rand = av_lfg_get(&s->r)/2; + + min = 999; + for (int i = 2; i >= 0; i--) { + riff = rand%s->numriffs; + if (s->last_note == 0) + return(riff); + dn = abs(s->last_note - s->riffs[riff*NPR]); + if (dn == 0) + dn = 6; + if (dn < min) { + bestriff = riff; + min = dn; + } + } + + return bestriff; +} + +/*Determine the energy of the player which will affect the number of rests and holding tones*/ +static int energy_calc(int i, int numbars) +{ + if (3*i < numbars) + return (100 - (90*i)/numbars); + else if (3*i > 2*numbars) + return (40 + (90*i)/numbars); + return 70; +} + +static void play_riff(int riff, int energy, int note_duration, int note_time, AtoneContext *s) +{ + int pnd = 0, next; + short pn = 0 ; + /*Beat importance values chosen such that off beat values are more likely to be skipped than on beat*/ + int biv[] = {28, 0, 7, 0, 14, 0, 7, 4}; + unsigned rand; + for (int i = 0; i < NPR; i++) + { + rand = av_lfg_get(&s->r)/2; + next = s->riffs[riff*NPR + i]; + if (next != H && next != R && ((energy + biv[i]) < rand%100)) + next = (rand < RAND_MAX/2)? H : R; + if (next == H) { + pnd ++; + continue; + } + + if (pn != R) { + schedule_noteon(0, pn, note_time, s->velocity, s); + note_time += pnd*note_duration; + schedule_noteoff(0, pn, note_time, s); + s->last_note = pn; + } + pn = next; + pnd = 1; + } + + if (pn != R && pn != H) { + schedule_noteon(0, pn, note_time, s->velocity, s); + note_time += pnd*note_duration; + schedule_noteoff(0, pn, note_time, s); + s->last_note = pn; + } + +} + +static int find_percussion_track(char *s) +{ + int i; + + for (i = 0 ; i < sizeof(percussion_tracks)/sizeof(percussion_tracks[0]) ; i++) + if (strcmp(percussion_tracks[i], s) == 0) + break; + + return i; +} +static void play_percussion(AtoneContext *s) +{ + int note_time = s->time_marker; + + switch (s->i) { + case 0: s->track = Track_1; break; + case 1: s->track = Track_2; break; + case 2: s->track = Track_3; break; + case 3: s->track = Track_4; break; + case 4: s->track = Track_5; break; + case 5: s->track = Track_6; break; + case 6: s->track = Track_7; break; + case 7: s->track = Track_8; break; + case 8: s->track = Track_9; break; + case 9: s->track = Track_10; break; + case 10: s->track = Track_11; break; + default: s->track = Track_12; break; + } + + for (int i = 0; i < s->track.length; i++) { + /*percussion instruments in channel 10 */ + schedule_noteon(9, s->track.note[i].instrument_1, note_time, s->percussion_velocity, s); + schedule_noteon(9, s->track.note[i].instrument_2, note_time, s->percussion_velocity,s); + schedule_noteon(9, s->track.note[i].instrument_3, note_time, s->percussion_velocity,s); + /*Multiply by 4 as quarter note takes 1 beat, Whole note takes 4 beats and so on*/ + note_time += 4*s->beat_dur/s->track.note[i].beat; + schedule_noteoff(9, s->track.note[i].instrument_1, note_time, s); + schedule_noteoff(9, s->track.note[i].instrument_2, note_time, s); + schedule_noteoff(9, s->track.note[i].instrument_3, note_time, s); + } +} + +/*Determine the pattern, tempo (to paly as 8th, 16th or 32nd notes) and add the riffs to sequencer +Refernce: http://peterlangston.com/Papers/amc.pdf */ +static void schedule_riff_pattern(AtoneContext *s) +{ + int note_time, note_duration, tempo, rpb, energy, riff; + unsigned rand = av_lfg_get(&s->r)/2; + note_time = s->time_marker; + tempo = 1; + + if (tempo > rand%3) + tempo--; + else if (tempo < rand%3) + tempo++; + tempo = tempo%3; + rpb = 1<beat_dur/(NPR*rpb); + energy = energy_calc(rand%s->numbars, s->numbars); + for (int r = 0; r < rpb; r++) { + riff = pick_riff(s); + play_riff(riff, energy, note_duration, note_time, s); + + } + + play_percussion(s); + s->time_marker += 4*s->beat_dur; +} + +static void sequencer_callback(unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data) +{ + schedule_timer_event(data); + schedule_riff_pattern(data); +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *outlink = ctx->outputs[0]; + AtoneContext *s = ctx->priv; + AVFrame *frame; + int nb_samples; + + if (!s->infinite && s->duration <= 0) { + return AVERROR_EOF; + } else if (!s->infinite && s->duration < s->nb_samples) { + nb_samples = s->duration; + } else { + nb_samples = s->nb_samples; + } + + if (!(frame = ff_get_audio_buffer(outlink, nb_samples))) + return AVERROR(ENOMEM); + + if (s->framecount%((int)s->changerate) == 0) { + schedule_riff_pattern(s); + schedule_timer_event(s); + } + + fluid_synth_write_float(s->synth, nb_samples, frame->data[0], 0, 2, frame->data[0], 1, 2); + + if (!s->infinite) + s->duration -= nb_samples; + + s->framecount++; + frame->pts = s->pts; + s->pts += nb_samples; + return ff_filter_frame(outlink, frame); +} + +static av_cold int query_formats(AVFilterContext *ctx) +{ + AtoneContext *s = ctx->priv; + static const int64_t chlayouts[] = { AV_CH_LAYOUT_STEREO, -1 }; + int sample_rates[] = { s->sample_rate, -1 }; + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE}; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + int ret; + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats (ctx, formats); + if (ret < 0) + return ret; + + layouts = avfilter_make_format64_list(chlayouts); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_rates); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static const AVFilterPad atone_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_props, + }, + { NULL } +}; + +AVFilter ff_asrc_atone = { + .name = "atone", + .description = NULL_IF_CONFIG_SMALL("Generate algorithmic riff music."), + .query_formats = query_formats, + .init = init, + .uninit = uninit, + .activate = activate, + .priv_size = sizeof(AtoneContext), + .inputs = NULL, + .outputs = atone_outputs, + .priv_class = &atone_class, +}; + + diff --git a/libavfilter/notedef.h b/libavfilter/notedef.h new file mode 100644 index 0000000000..b7f4071b22 --- /dev/null +++ b/libavfilter/notedef.h @@ -0,0 +1,264 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFILTER_NOTEDEF_H +#define AVFILTER_NOTEDEF_H +#include +#include + +/*Define notes as per the General Midi specifications +*_ = minus, s = sharp, b = flat +* H = hold tone, R = Rest*/ +enum notes{C_1, Cs_1, Db_1 = 1, D_1, Ds_1, Eb_1 =3, E_1, F_1, Fs_1, Gb_1 = 6, G_1, Gs_1, Ab_1 = 8, A_1, As_1, Bb_1 =10, B_1, + C0, Cs0, Db0 = 13, D0, Ds0, Eb0 = 15, E0, F0, Fs0, Gb0 = 18, G0, Gs0, Ab0 = 20, A0, As0, Bb0 = 22, B0, + C1, Cs1, Db1 = 25, D1, Ds1, Eb1 = 27, E1, F1, Fs1, Gb1 = 30, G1, Gs1, Ab1 = 32, A1, As1, Bb1 = 34, B1, + C2, Cs2, Db2 = 37, D2, Ds2, Eb2 = 39, E2, F2, Fs2, Gb2 = 42, G2, Gs2, Ab2 = 44, A2, As2, Bb2 = 46, B2, + C3, Cs3, Db3 = 49, D3, Ds3, Eb3 = 51, E3, F3, Fs3, Gb3 = 54, G3, Gs3, Ab3 = 56, A3, As3, Bb3 = 58, B3, + C4, Cs4, Db4 = 61, D4, Ds4, Eb4 = 63, E4, F4, Fs4, Gb4 = 66, G4, Gs4, Ab4 = 68, A4, As4, Bb4 = 70, B4, + C5, Cs5, Db5 = 73, D5, Ds5, Eb5 = 75, E5, F5, Fs5, Gb5 = 78, G5, Gs5, Ab5 = 80, A5, As5, Bb5 = 82, B5, + C6, Cs6, Db6 = 85, D6, Ds6, Eb6 = 87, E6, F6, Fs6, Gb6 = 90, G6, Gs6, Ab6 = 92, A6, As6, Bb6 = 94, B6, + C7, Cs7, Db7 = 97, D7, Ds7, Eb7 = 99, E7, F7, Fs7, Gb7 = 102, G7, Gs7, Ab7 = 104, A7, As7, Bb7 = 106, B7, + C8, Cs8, Db8 = 109, D8, Ds8, Eb8 = 111, E8, F8, Fs8, Gb8 = 114, G8, Gs8, Ab8 = 116, A8, As8, Bb8 = 118, B8, + C9, Cs9, Db9 = 121, D9, Ds9, Eb9 = 123, E9, F9, Fs9, Gb9 = 126, G9, H, R}; + +const char *GM_instrument_list[128] = {"Acoustic-Grand", "Bright-Acoustic", "Electric-Grand", "Honky-Tonk", "Electric-Piano-1", "Electric-Piano-2", +"Harpsichord", "Clav", "Celesta", "Glockenspiel", "Music-Box", "Vibraphone", "Marimba", "Xylophone", "Tubular-Bells", "Dulcimer", "Drawbar-Organ", +"Percussive-Organ", "Rock-Organ", "Church-Organ", "Reed-Organ", "Accordion", "Harmonica", "Tango-Accordion", "Acoustic-Guitar-nylon", "Acoustic-Guitar-steel", +"Electric-Guitar-jazz","Electric-Guitar-clean", "Electric-Guitar-muted", "Overdriven-Guitar", "Distortion-Guitar", "Guitar-Harmonics", +"Acoustic-Bass", "Electric-Bass-finger", "Electric-Bass-pick", "Fretless-Bass", "Slap-Bass-1", "Slap-Bass-2", "Synth-Bass-1", "Synth-Bass-2", + "Violin", "Viola", "Cello", "Contrabass", "Tremolo-Strings", "Pizzicato-Strings", "Orchestral-Harp", "Timpani", "String-Ensemble-1", "String-Ensemble-2", + "SynthStrings-1", "SynthStrings-2", "Choir-Aahs", "Voice-Oohs", "Synth-Voice", "Orchestra-Hit", "Trumpet", "Trombone", "Tuba", + "Muted-Trumpet", "French-Horn", "Brass-Section", "SynthBrass-1", "SynthBrass-2", "Soprano-Sax", "Alto-Sax", "Tenor-Sax", "Baritone-Sax", + "Oboe", "English-Horn", "Bassoon", "Clarinet", "Piccolo", "Flute", "Recorder", "Pan-Flute", "Blown-Bottle", "Shakuhachi", "Whistle", "Ocarina", + "Lead-1-square", "Lead-2-sawtooth", "Lead-3-calliope", "Lead-4-chiff", "Lead-5-charang", "Lead-6-voice", "Lead-7-fifths", "Lead-8-bass+lead", + "Pad-1-new-age", "Pad-2-warm", "Pad-3-polysynth", "Pad-4-choir", "Pad-5-bowed", "Pad-6-metallic", "Pad-7-halo", "Pad-8-sweep", + "FX-1-rain", "FX-2-soundtrack", "FX-3-crystal", "FX-4-atmosphere", "FX-5-brightness", "FX-6-goblins", "FX-7-echoes", "FX-8-sci-fi", + "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe", "Fiddle", "Shanai", "Tinkle-Bell", "Agogo", "Steel-Drums", "Woodblock", "Taiko-Drum", + "Melodic-Tom", "Synth-Drum", "Reverse-Cymbal", "Guitar-Fret-Noise", "Breath-Noise", "Seashore", "Bird-Tweet", "Telephone-Ring", "Helicopter", + "Applause", "Gunshot"}; + +enum percussion_notes{Metronome_Click = 33, Metronome_Bell, Acoustic_Bass_Drum, Bass_Drum_1, Side_Stick, Acoustic_Snare, Hand_Clap, Electric_Snare, Low_Floor_Tom, + Closed_Hi_Hat, High_Floor_Tom, Pedal_Hi_Hat, Low_Tom, Open_Hi_Hat, Low_Mid_Tom, Hi_Mid_Tom, Crash_Cymbal_1, High_Tom, Ride_Cymbal_1, Chinese_Cymbal, + Ride_Bell, Tambourine, Splash_Cymbal, Cowbell, Crash_Cymbal_2, Vibraslap, Ride_Cymbal_2, Hi_Bongo, Low_Bongo, Mute_Hi_Conga, Open_Hi_Conga, Low_Conga, + High_Timbale, Low_Timbale, High_Agogo, Low_Agogo, Cabasa, Maracas, Short_Whistle, Long_Whistle, Short_Guiro, Long_Guiro, Claves, Hi_Wood_Block, + Low_Wood_Block, Mute_Cuica, Open_Cuica, Mute_Triangle, Open_Triangle}; + +/*Assuming maximum of three percussion instruments can be played at the same time*/ +typedef struct{ + unsigned int instrument_1; + unsigned int instrument_2; + unsigned int instrument_3; + unsigned int beat; +}percussion_structure; + +typedef struct +{ + unsigned int length; + percussion_structure note[]; +}percussion; + +/*Define some drum beats... +Beat: Whole note = 1, Half note = 2, Quater note = 4, ..., Number of beats: Whole note = 4/1, Half note = 4/2, Quater note = 4/4 +Note 1 does not produce any sound*/ +#define jazz1 {12, {{Bass_Drum_1, Ride_Cymbal_2, 1, 12},\ + {1, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, 1, 12}, \ + {Bass_Drum_1, Ride_Cymbal_2, 1, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, 1, 12}}} +#define jazz2 {12, {{1, Ride_Cymbal_2, 1, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, Ride_Cymbal_2, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, Ride_Cymbal_2, 1, 12}}} +#define jazz3 {12, {{1, Ride_Cymbal_2, 1, 12},\ + {1, 1, 1, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}}} +#define jazz4 {12, {{1, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}}} +#define jazz5 {12, {{Electric_Snare, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}}} +#define jazz6 {12, {{1, Ride_Cymbal_2, 1, 12}, \ + {1, 1, 1, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {1, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {Electric_Snare, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}, \ + {1, 1, 1, 12}, \ + {Bass_Drum_1, 1, 1, 12}, \ + {Electric_Snare, Ride_Cymbal_2, Pedal_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, Ride_Cymbal_2, 1, 12}}} +#define rock1 {8, {{Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}}} +#define rock2 {8, {{Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}}} +#define rock3 {8, {{Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}}} +#define rock4 {8, {{Bass_Drum_1, Acoustic_Snare, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, Acoustic_Snare, Closed_Hi_Hat, 8}, \ + {1, 1, Closed_Hi_Hat, 8}, \ + {1, Acoustic_Snare, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}, \ + {1, Acoustic_Snare, Closed_Hi_Hat, 8}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 8}}} +#define shuffle {12, {{Bass_Drum_1, 1, Closed_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, 1, Closed_Hi_Hat, 12}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, 1, Closed_Hi_Hat, 12}, \ + {Bass_Drum_1, 1, Closed_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, 1, Closed_Hi_Hat, 12}, \ + {Acoustic_Snare, 1, Closed_Hi_Hat, 12}, \ + {1, 1, 1, 12}, \ + {1, 1, Closed_Hi_Hat, 12}}} +#define metronome {4, {{Metronome_Click, 1, 1, 4}, \ + {Metronome_Click, 1, 1, 4}, \ + {Metronome_Click, 1, 1, 4}, \ + {Metronome_Click, 1, 1, 4}}} + +const percussion Track_1 = jazz1; +const percussion Track_2 = jazz2; +const percussion Track_3 = jazz3; +const percussion Track_4 = jazz4; +const percussion Track_5 = jazz5; +const percussion Track_6 = jazz6; +const percussion Track_7 = rock1; +const percussion Track_8 = rock2; +const percussion Track_9 = rock3; +const percussion Track_10 = rock4; +const percussion Track_11 = shuffle; +const percussion Track_12 = metronome; + +const char *percussion_tracks[] = {"Jazz1", "Jazz2", "Jazz3", "Jazz4", "Jazz5", "Jazz6", "Rock1", "Rock2", "Rock3", "Rock4", "Shuffle", "Metronome"}; + +/*Define the riffs : 8 notes per riff +Refernce: http://peterlangston.com/Papers/amc.pdf */ +#define NPR 8 +const int riff[] = {Eb4, D4, A4, F4, E4, C5, A4, A4, /* 0 */ + F4, A4, Eb5, D5, E4, A4, C5, A4, /* 1 */ + Ab4, A4, H, G5, H, Eb5, C5, E5, /* 2 */ + Ab4, A4, B4, C5, Eb5, E5, Ab5, A5, /* 3 */ + A4, Bb4, B4, C5, Db5, D5, Eb5, E5, /* 4 */ + A4, Bb4, B4, C5, E5, Eb5, D5, C5, /* 5 */ + A4, B4, C5, A4, B4, C5, D5, B4, /* 6 */ + A4, B4, C5, D5, Eb5, E5, Eb5, C5, /* 7 */ + A4, C5, D5, Eb5, Gb5, Ab5, A5, C6, /* 8 Pat Metheny */ + A4, C5, Eb5, B4, D5, F5, Eb5, C5, /* 9 */ + A4, C5, E5, G5, B5, A5, G5, E5, /* 10 */ + A4, C5, E5, A5, G5, Eb5, C5, A4, /* 11 */ + B4, A4, B4, C5, B4, A4, B4, C5, /* 12 */ + B4, A4, B4, C5, B4, C5, B4, A4, /* 13 */ + B4, A4, B4, C5, D5, C5, D5, Eb5, /* 14 */ + C5, Ab4, A4, G5, F5, Gb5, Eb5, E5, /* 15 Marty Cutler */ + C5, D5, C5, B4, C5, B4, A4, H, /* 16 */ + C5, D5, Eb5, C5, D5, Eb5, F5, D5, /* 17 */ + D5, C5, A4, C5, E5, Eb5, D5, C5, /* 18 */ + D5, C5, D5, Eb5, D5, C5, D5, Eb5, /* 19 */ + D5, Eb5, E5, F5, Gb5, G5, Ab5, A5, /* 20 */ + D5, Eb5, G5, Eb5, D5, C5, B4, C5, /* 21 Charlie Keagle */ + D5, Eb5, A5, D5, H, C5, A4, E4, /* 22 */ + D5, E5, G5, E5, C5, H, D5, A5, /* 23 Lyle Mays/Steve Cantor */ + Eb5, D5, Eb5, D5, H, C5, A4, H, /* 24 */ + Eb5, D5, Eb5, F5, Eb5, D5, C5, B4, /* 25 */ + Eb5, E5, D5, C5, B4, A4, Ab4, A4, /* 26 Richie Shulberg */ + Eb5, E5, A5, C5, B4, E5, A4, A4, /* 27 */ + Eb5, Gb5, E5, A4, B4, D5, C5, E4, /* 28 Django Rheinhart */ + E5, A4, C5, Ab4, B4, G4, Gb4, E4, /* 29 David Levine */ + E5, Eb5, D5, C5, B4, C5, D5, F5, /* 30 */ + G5, E5, D5, B4, Eb5, H, C5, A4, /* 31 */ + G5, E5, D5, Gb5, C5, H, A4, H, /* 32 Mike Cross */ + Ab5, A5, Ab5, A5, Ab5, A5, Ab5, A5, /* 33 Django Rheinhart */ + A5, E5, C5, G4, C5, E5, A5, A5, /* 34 Django Rheinhart */ + A5, E5, C5, A4, G5, Eb5, C5, A4, /* 35 */ + A5, B5, G5, E5, F5, Gb5, G5, Ab5, /* 36 */ + B5, C6, A5, E5, G5, B5, A5, H, /* 37 */ + B5, D6, C6, E5, Ab5, B5, A5, C5, // 38 Django Rheinhart + C6, B5, A5, G5, Gb5, E5, Eb5, C5} ;/* 39 */ + +typedef struct lsys +{ + int note; + int dur; +}lsys; +#define L_MAX_LENGTH 45000 +#endif/*AVFILTER_NOTEDEF_H*/ + diff --git a/libavfilter/version.h b/libavfilter/version.h index 37015085fa..308fbe07c3 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFILTER_VERSION_MAJOR 7 -#define LIBAVFILTER_VERSION_MINOR 86 +#define LIBAVFILTER_VERSION_MINOR 87 #define LIBAVFILTER_VERSION_MICRO 100