From 10e8c1e82a0bf610cb6be0c5a28312ccc5096a3d Mon Sep 17 00:00:00 2001 From: Mario Ortiz Manero Date: Tue, 31 Dec 2019 16:58:58 +0100 Subject: [PATCH] youtube-dl integration & more intervals --- CMakeLists.txt | 2 +- README.md | 17 ++++++ apps/CMakeLists.txt | 2 +- apps/images/.gitignore | 5 ++ apps/main.c | 3 +- apps/main.py | 10 +--- images/144000.png | Bin 5659 -> 6389 bytes images/144000_original.png | Bin 5896 -> 6497 bytes images/288000.png | Bin 0 -> 4980 bytes images/288000_original.png | Bin 0 -> 5197 bytes images/480000.png | Bin 0 -> 7042 bytes images/480000_original.png | Bin 0 -> 7037 bytes .../download/linux_download.h | 2 + include/vidify_audiosync/global.h | 8 ++- src/CMakeLists.txt | 4 +- src/audiosync.c | 11 ++-- src/bind.c | 6 +- src/capture/linux_capture.c | 1 + src/cross_correlation.c | 17 +++--- src/download/linux_download.c | 52 +++++++++++++++++- tests/CMakeLists.txt | 4 +- 21 files changed, 107 insertions(+), 37 deletions(-) create mode 100644 apps/images/.gitignore create mode 100644 images/288000.png create mode 100644 images/288000_original.png create mode 100644 images/480000.png create mode 100644 images/480000_original.png diff --git a/CMakeLists.txt b/CMakeLists.txt index a34771a..c1deb7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(VidifyAudiosync LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Debug configuration -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -g3 -std=c11 \ +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -g3 -std=c99 \ -DDEBUG -fsanitize=undefined -fsanitize=address") # Release configuration set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wall -Wextra -O3") diff --git a/README.md b/README.md index 6ca4178..90afbfb 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,23 @@ The only exported method is `get_lag(url: str)`, which returns the displacement There's a simple example implementation in the [example.py](https://github.com/marioortizmanero/vidify-audiosync/blob/master/examples/example.py) file. +There are 2 apps to try: + +* `apps/main.c`: used to debug more easily. You can run it with: + +```shell +mkdir build +cd build +mkdir images +cmake .. +make +./apps/main "SONG NAME" +``` + +Use `-DCMAKE_BUILD_TYPE=Debug` to enable debugging and save plots into the images directory. You'll need `gnuplot` installed for that. + +* `apps/main.py`: the actual module usage. You can simply use `python main.py "SONG NAME"` + ## How it works *I'll try to explain it as clearly as possible, since this took me a lot of effort to understand without prior knowledge about the mathematics behind it. If someone with a better understanding of the calculations performed in this module considers that the explanation could be improved, please [create an issue](https://github.com/marioortizmanero/vidify-audiosync/issues) to let me know.* diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 60f4fcd..0fdbf00 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -4,6 +4,6 @@ add_executable( ${HEADER_LIST} ) -target_compile_features(main PRIVATE c_std_11) +target_compile_features(main PRIVATE c_std_99) target_link_libraries(main PRIVATE vidify_audiosync fftw3 m pthread) diff --git a/apps/images/.gitignore b/apps/images/.gitignore new file mode 100644 index 0000000..702f12b --- /dev/null +++ b/apps/images/.gitignore @@ -0,0 +1,5 @@ +# Ignore everything in this directory +*.png + +# Except this file +!.gitignore diff --git a/apps/main.c b/apps/main.c index afa4601..44610b8 100644 --- a/apps/main.c +++ b/apps/main.c @@ -5,10 +5,11 @@ int main(int argc, char *argv[]) { if (argc != 2) { - printf("Usage: %s URL\n", argv[0]); + printf("Usage: %s \"TITLE\"\n", argv[0]); exit(1); } + printf("Running get_lag\n"); int ret = get_lag(argv[1]); printf("Returned value: %d\n", ret); diff --git a/apps/main.py b/apps/main.py index 9c7373a..d4d5287 100644 --- a/apps/main.py +++ b/apps/main.py @@ -10,15 +10,7 @@ " background.") exit() -# Obtaining an URL from a song name with youtube_dl -ytdl_opts = { - 'format': 'bestaudio' -} -with youtube_dl.YoutubeDL(ytdl_opts) as ytdl: - info = ytdl.extract_info(f"ytsearch:{sys.argv[1]}", download=False) -url = info['entries'][0]['url'] - # After this is printed, the music should start playing in the background too print("Running audiosync.get_lag") -ret = audiosync.get_lag(url) +ret = audiosync.get_lag(sys.argv[1]) print(f"Returned value: {ret}") diff --git a/images/144000.png b/images/144000.png index 238da608d17bb2c552d834c09120dee9dd6bd90d..173bdfa5aa0fbbe2fb9fcaa6d34b7d68c33cfab1 100644 GIT binary patch literal 6389 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 ALI3~& literal 5659 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 g;s5(~`q%2S%!V}^EspF literal 5896 zcmcgwc|26#-=BNkVVG!?u`e^0>{}udE+$K&Az8AQr9_datT$P*rIKXJv?x)LJ%!sM z$u^ZJ%a@crOQG!ZT)w~G@7e!&{(0tgXYToY&iU+T&Uv4cK({jG<`U+@;c(pMW;7cd z4n%M`V1U4ealp+=ofx4>-)Fmr#bRL`27|HwLUA~Rh2mJasVNl3y?u)_Joc4^Qg8^2 zA}lp`BngLu5gZF)MX@^a6%;U0cz}t?2@4BrXlPhkT6%kXM@2F~khst6wr;p0PK>_HHB6me%E>;A(m2KKnK7y&F4WnuBK(AKJ(Gprd#W$O#p zi&nHGoCPyjl)Ab)2?>e3ygUN~gZldV{{DV9H#gkPpu}qrMzOFt1I!$Qa5$dV>t7&U zkw*lFBcC&;8QPxBnat%3y|atN-k?*xc?6AHSTnuo$bG}|(e;=;pZ>UR^JHH=@t|eu ztsti6KYXf1Qn!cMr49X3?Y1~C^6Ra5@Xb%(PTizZpu2qodZuHAn*b^$xbsKk>?sG8 zppX}&%Y}W*`f(96Jv1l=X~Fwd#uErYCh@Z7d3%<;GfV7XSOc!neUTElo`r9EWZzcVUo0N;Ick6tz&l$H{ZlTjr zv!cKYi72mwEU)%IdGlc>v;R1ufe#*YgV6@#KYp$q(zjgpDN{Uw7tKgEglEkDI2^ch zXmugX`vUUqD#kF!7;E9jf439`617z_H36cCoe?jIJxT^C8iAU6Y4xm#4 zPgc@v0tp0(-x5tH-`5FY>{Bylkoh}>Kwy&BFM1M*x z1}{24o-6f`;R8GdX0C*B3Q=rVdP7!A_gLDNK4=T&tc*_VsE&wfk)c^B94X(+ z)u8k2$*C>B7Pc^D&=kHmN7HN*gPw2tDEezY!$T`Fhz(q#rVsL|(hQnIht70S7!o$} zR%3R~`YSwFirZVI)@hZYcwQT!I|ps#d4Q;Ewu#25giQJ%iLR&NKmuJQ-Lt>r_q{;x z;=`!}Lx%8B3t~t(n}GO}W;o#gBXtWuwlpl;t;l~-CJA;&|92~Q zRoorec$va~YxuxF6N`kN-|&Qe!xQ1ZJ)vv}pU>b6xKVI#sD-9UC?Jz-sx7#xZxj~o zx>-0uW*S1a+|O?#lRr?qG_oYajt_in)s>|xLWB2P6RNe2EQJ|7mq3t17_rU0LEXJT z4szx#QDO0bB)XzP93l=Lgha1T{8|)a&N$NGM+Fe%T}qactEOy1|@W%5FN9Czgg0&al-URu#TkON@zqB0N^jC>>aWRM-J+ffd1 z9An|2j%FhmpyHKC^nGW6k0MggX&gYlO``LF3N$K16tcajaERlh5)TkdVc6N7N48-3 zIIhA7k^Wb|5v&skZ3+sLwB-kP1+W3N@qK3S>RU6A{j(C4VPj`~SB?>-ILIkD(>J8Y z3FKpX_`$@BvhHuc5vR=wax(XjuZgo_o+LUK=!^MuF`FPbs2~gOB`CO`M{HhlEpX|W z;K4#qDuV!Zyc;hxhAl8Bh`^q|HJLe~w_(^E2Nue(^Un+wY2{~L4K17=CNcL*f?6%Z ziDAq3e>tL;8>sH4x(35)PQy;75Dm8A8zDX}-CbXd;K4+Crh07;M^}X*mUo&pe1t>- z{LK%dl3oB2`XLC3MwM)He^o*{l1yUiwWJ{$JEdFp8?{taB7_2gkWb1C`5=v_n=T-P zqbcLDN1=WD(ZLVkrK-VD;PGO05>(CskjqHSn+Z|Jh=P(tVA2q7 z_y>1eL;@oFGy(A_B{9Vz+ZH1@%sY43V8R4c;J7D`B_qpmWAb~;$TPYwB~jgZ3$!jE zzmRMAO$VLwGWG@%3NFVXr?!wwV7OHcDu)2Q*wt!8eB#Dd7ZmxlxNnKe7!9H@?yEt& zIlxdZ3v)P6FCMx1@(r!x^JTEEZeoV!2N<8|kJuIwOC8W5F%NteOhBIfEzzh6&80sh zm8AZ>cD)o?d+k7GI`w8Dmcdl~-0uK=aPMalbHrrO4pivmw@1~CzegpzszQ9xi14wK zfZLP8S-0MMh;V{6-mmVgPyvxJ`jaG8gSZq}oqvL#E6sNhza}H&{zS!{<=vUu!%xrG zW#d}Vqp3r48YUB9Xpv&fsUFweesb@-CqttW&%s!w4I2fx=@2n5Kc= zmZ*tgUc+SiNUuJqARV{0L~zB4AXrpQgKQ_O4+o2UmGL#}mAHcg-zc^{jeu;;o?k-r zPbg3sVmk%s&-D8n`u3x>YF{P@^6pdtddRJ%0`0Exmz<+jmo_(oQz=)z$BJIMayXD< zZI4{rtt|F~K>WG1PS7gleW+&0a=OG;W@+^V=jc(!J)}AFn>S$Ub-F9DE30C6iH_7j z=SRP~H%Bw=TO=Rdw&JU@&aEGGzO-8tuatdELpI2#4diKFAXFE;u|vP9kLykreafg( zU)p4|Tp=h{p1j+>w;3Xr6z`9_jkuL@w1ZaZPY$&;Pw6O#03%X1<@To^P3U)cT=C1| zSXkv+=u22jDmzhQY>j%X%`NIXNV^-*SC6Dh*tgjp(=ho4*Dhu5PBIMEm47%MT9HSQ zuetHHFZh?3w~KRsy#G#qH~GdZTB~w{H6YLG&hSh>#a+f)Z4TY0XO;5>@!+_aCld% zAG#(G^NG^u@IQ!>pJJfqC-91atPx$;;N94KqWYY&_O>{$yPX{>i*Gj@Y|WdpZlS1v{nL>qbgpoNC^F zkI7u^x_$2@@QKmgClkBoT0A=!x~m3{pkpsCWajx=UiUuM_u`Sit3b!2PvStbGcww-imAK5M&1a42tAPfF4~C+59U zT+cOITJ=5N%Bc55gC#MO{4scFQNSZO|8S+Zfk~%V58-otQDT!9+Ug__)*xmQSus+p zJ#o(|S}!@^Ui2pgzv9xoTE~(|S*uf313$dJemN1gMP7cYpeB8g>-}nC*|RP3_Piy! z?|P0JJE5)5+Db+Cj-1F)vCE7(v?rGoP}`I-@3iO{_%bY9PvD$*Ne>*eH6SS2@2Y-6 z{E>3jjhlNqep09G(u^!4$Bx~&fUGL;i0AKazlDUg=2ICaA8wqztu3G;#Sq5kbwHDP zmWdcwby;b~pyub;zK zKlwPrZnLF8;7s11PU4cZBtzz#V63p@v_x*Mi9g}!+?_ZKJNO)g(@GF_U_bPl%>3ax z9+KSiu-Pfl4Sd{h^5J4ngxLonsN-Uf5)nwPMiB8f;!9%nE;A4OoLz6Ie*$6jlt^Iq z1fjsKKNzz8a*CF7&*R6gh|ajTzvT_G%PoP37*`l>IAiAwM8rNOj{3xC;dk7EMD;aC zEYae@;k=xnL2-~r6}9hvCz!Ilj02aNgg$&AGu@7c1GR5jizcE(onbK&UCQ4DcB2W< z%Oao-GmArLdiLJL*EtWF5*TjMHQ_k7y8jjVez!h2exJ&~6AJR;5Pk|HQW!i$vW34D zU(yi)m-fx-m>oZdA*qYfjK;g_%2|khTHQ<1jHo)KWJDG)gi|Z9ZB!V12gCV0pljG> zuE!qnfkbBq6|jYLVqL*K@-AN-2M+yZrQZ|syi|J5N~gRIRCau)Pp ztK2_C756c^NlYrGL$HBg4HgG0m4;0U>#~!i7>00bNi&9^#2zc~l7Pv8ttEc<-iVGg zhIj0r3EgpG^L766F*aHWS zf2T6ka6s^{zgSd;^m>Ct7bMZ)t=2Fr;VU$^n*D}EmmvZe5ZP<@5)_86onOa&av)HF z;T{O|-GgC}7X+4hU%JQElFE|x5gQmz4g!L)5d?4?Lq;U1Bf%HiK{&d3gS^ZH*`H5c zKuU2@!4J?=Z!D>qF(aMs+JJ zh&m?Q0)Yr}JR(eC2tpl{=g9d~RT3Qp3lYQyB#!zg+Zni~1rJAGT> zv8LvS;iBv@A60XZkGr9Aqrk$)K8~6O+FUSPThK#v(3<7@okk8h;Io!)ibWz2d2pDgg+6Al&RAnv-$Na+K@*Q)0LsW7tyyte6M^P3$R)DH$^#|N8ST?Z z+}LIkU3sDlzjEqT^h&MoQ*BPiFKgJ|pE*DApTYBuSfq^jUU9j<0*kNN2>of-+w;=2 z)4H972bY?;6d3p0l4sS7z z8lJ*9#1HPp@Uk*-qbliMB>EPtu#W3k+zHE52!(ON{T&$kfEx&AW7~TkD<)){LKKSI zIPM5;95OsM09YKAft`bd|L$-Q2H7XIppH$(@No=`Z(6t6T4D=rB7nZwKAbSteicH1`1n3cj`~oD0-d@>9mfBwT zBJ_+NZqK{keX6e>`UAkqljo!qgmnF@U9US81pj%()tfpbwcPmK%TC|BXezwS@{Hk! zTPfq26@Sh-cWal8pAb1X{FjwxZ{eBIF5l-z6sNoDxKkqa+PiYE8sGH#^ib0=cqH4u zrk!28+`87ycxYjlxZ`{zHT`)?VM|NXcCDVVo`7*o=6>X44|CL>$e;Q{;-lVQGxkuB37%rp7UfxighzbyJnRnz8F~Cj93@R zo>~_<9d$CNTTs{Lvq}2UqUp`mPgUJQ-J_T1C+>0w*0&uG{DH}ce=%q+TX|SB+d90o z>cb}5T~NB_&@dFdB7phcpnzQ_Rc z%^jV?QQCDpvl(8Q2Yhsi+U4&hr@J0=S4H~wFvq$+zRfBW8xl&D%7OgaI!;w72c8+o zbK3*QN47S8+vx+4F?D68zuRpx+Q$lY`~B1+wa{BBreUJn$G8neCYxM8PXE&K2Dy5K zpwnYrmE4Vyllarq_C)FUwBR%OOA z-t@@Lzoh=|=P6n5qIW8`m9e{AXj44bUAh;-B-rdMPbT)f?Ng;~W}EIPCIai(w-@m{ zS-4wY;!#q#;?%7Gi;}0SL#KP>?W@UM5@9;?6Gm``){Z6eKj+iGzx@_DUZL{^(o%Ph PuQSc}SkWFExkvvSvX1?$ diff --git a/images/288000.png b/images/288000.png new file mode 100644 index 0000000000000000000000000000000000000000..d8d635c0487b3feeb884e94b81dfb8d9ce4ad8ea GIT binary patch literal 4980 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 literal 0 HcmV?d00001 diff --git a/images/288000_original.png b/images/288000_original.png new file mode 100644 index 0000000000000000000000000000000000000000..d24c4044daf7978ebf1ee2f963ff8aa8789aca3c GIT binary patch literal 5197 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 N#KhA0-XXX6{{V1D@Dcz3 literal 0 HcmV?d00001 diff --git a/images/480000.png b/images/480000.png new file mode 100644 index 0000000000000000000000000000000000000000..269246cf6721796561f1be781fc1bcde8ece71b6 GIT binary patch literal 7042 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 E1J%UYl>h($ literal 0 HcmV?d00001 diff --git a/images/480000_original.png b/images/480000_original.png new file mode 100644 index 0000000000000000000000000000000000000000..0b5cc49be771612f02a216e7abd23b142dba28a2 GIT binary patch literal 7037 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 #include "../../include/vidify_audiosync/global.h" #include "../../include/vidify_audiosync/ffmpeg_pipe.h" +#include "../../include/vidify_audiosync/capture/linux_capture.h" // NOTE: for now requires to change the captured sink in pavucontrol to diff --git a/src/cross_correlation.c b/src/cross_correlation.c index 6c7ecad..3c4b747 100644 --- a/src/cross_correlation.c +++ b/src/cross_correlation.c @@ -12,7 +12,6 @@ #include "../include/vidify_audiosync/global.h" - // Data structure used to pass parameters to concurrent FFTW-related functions. struct fftw_data { double *real; @@ -54,6 +53,10 @@ static void *fft(void *thread_arg) { // calculate the circular cross-correlation rather than the regular // cross-correlation. // +// Note: if debugging mode is enabled, plots of each run will be saved in an +// images directory. The titles assume that `input1` is the captured data, +// and `input2` is the downloaded data. +// // Returns the lag in frames the second data set has over the first one, with // a confidence between -1 and 1. // @@ -83,13 +86,13 @@ int cross_correlation(double *input1, double *input2, const size_t input_length, FILE *gnuplot = popen("gnuplot", "w"); fprintf(gnuplot, "set term 'png'\n"); fprintf(gnuplot, "set output 'images/%ld_original.png'\n", input_length); - fprintf(gnuplot, "plot '-' with lines title 'data1', '-' with lines title 'data2'\n"); + fprintf(gnuplot, "plot '-' with lines title 'downloaded', '-' with lines title 'captured'\n"); for (size_t i = 0; i < input_length; ++i) - fprintf(gnuplot, "%f\n", data1[i]); + fprintf(gnuplot, "%f\n", data2[i]); fprintf(gnuplot, "e\n"); // The second audio file starts at samplesDelay for (size_t i = 0; i < input_length; ++i) - fprintf(gnuplot, "%f\n", data2[i]); + fprintf(gnuplot, "%f\n", data1[i]); fprintf(gnuplot, "e\n"); fflush(gnuplot); pclose(gnuplot); @@ -207,13 +210,13 @@ int cross_correlation(double *input1, double *input2, const size_t input_length, gnuplot = popen("gnuplot", "w"); fprintf(gnuplot, "set term 'png'\n"); fprintf(gnuplot, "set output 'images/%ld.png'\n", input_length); - fprintf(gnuplot, "plot '-' with lines title 'data1', '-' with lines title 'data2'\n"); + fprintf(gnuplot, "plot '-' with lines title 'downloaded', '-' with lines title 'captured'\n"); for (size_t i = 0; i < input_length; ++i) - fprintf(gnuplot, "%f\n", data1[i]); + fprintf(gnuplot, "%f\n", data2[i]); fprintf(gnuplot, "e\n"); // The second audio file starts at samplesDelay for (size_t i = 0; i < input_length; ++i) - fprintf(gnuplot, "%f\n", data2[i]); + fprintf(gnuplot, "%f\n", data1[i]); fprintf(gnuplot, "e\n"); fflush(gnuplot); pclose(gnuplot); diff --git a/src/download/linux_download.c b/src/download/linux_download.c index 7666cd2..3ba608b 100644 --- a/src/download/linux_download.c +++ b/src/download/linux_download.c @@ -1,20 +1,66 @@ +#define _GNU_SOURCE #include #include #include +#include #include "../../include/vidify_audiosync/global.h" #include "../../include/vidify_audiosync/ffmpeg_pipe.h" +#include "../../include/vidify_audiosync/download/linux_download.h" + +#define MAX_LONG_URL 4086 +#define MAX_LONG_COMMAND 4086 void *download(void *arg) { struct down_data *data; data = (struct down_data *) arg; + char *url = malloc(sizeof(char) * MAX_LONG_URL); + if (url == NULL) { + perror("malloc"); + goto finish; + } + + if (get_audio_url(data->yt_title, &url) < 0) { + fprintf(stderr, "Could not obtain youtube url.\n"); + goto finish; + } + char *args[] = { - "ffmpeg", "-y", "-to", "15", "-i", data->url, "-ac", - NUM_CHANNELS_STR, "-r", SAMPLE_RATE_STR, "-f", "f64le", "pipe:1", - NULL + "ffmpeg", "-y", "-to", "15", "-i", url, "-ac", NUM_CHANNELS_STR, "-r", + SAMPLE_RATE_STR, "-f", "f64le", "pipe:1", NULL }; read_pipe(data->th_data, args); +finish: + if (url) free(url); pthread_exit(NULL); } + + +// Obtains the audio direct link with Youtube-dl. +int get_audio_url(char *title, char **url) { + int ret = -1; + + // Creating the full command + char command[MAX_LONG_COMMAND]; + strcpy(command, "youtube-dl -g -f bestaudio ytsearch:\""); + strcat(command, title); + strcat(command, "\""); + + // Run the command and read the output + FILE *fp = popen(command, "r"); + if (fp == NULL) { + fprintf(stderr, "Failed to run command\n" ); + goto finish; + } + printf("Getting url 1 %s\n", command); + fscanf(fp, "%s", *url); + printf("Getting url 2\n"); + pclose(fp); + + ret = 0; + +finish: + return ret; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3499644..11973cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,8 +5,8 @@ add_executable( ${HEADERS} ) -# Minimum C11 required. Also listing the used libraries. -target_compile_features(tests PRIVATE c_std_11) +# Minimum C99 required. Also listing the used libraries. +target_compile_features(tests PRIVATE c_std_99) target_link_libraries(tests PRIVATE vidify_audiosync fftw3 m pthread) # Adding the tests one by one for the make command: