vj节点_创意编码—如何在JavaScript中创建VJ引擎

本文介绍了如何使用JavaScript创建一个VJ引擎,用于创意编码。作者乔治·加利分享了他的经验,包括如何动态注入JavaScript到网页,如何结构化内容以及如何检索和播放内容。文章详细解释了内容的组织方式,如何通过键盘控制选择内容,以及如何通过注入脚本来访问和播放文件。此外,还提到了其他有用的功能,如调整输入音量和应用音频和视觉过滤器。
摘要由CSDN通过智能技术生成

vj节点

by George Gally

通过乔治·加利

创意编码—如何在JavaScript中创建VJ引擎 (Creative Coding — How to create a VJ engine in JavaScript)

了解如何将JavaScript动态注入网页 (Learn how to dynamically inject JavaScript into webpages)

For years I’ve been using the browser for my performances and installations using my own simple homegrown VJ engine. And now, after you learn a few simple tricks, you can too…

多年来,我一直使用自己的简单本地VJ引擎将浏览器用于表演和安装。 现在,在您学习了一些简单的技巧之后,您也可以...

快速介绍 (A quick intro)

Firstly, what is a VJ engine? you might ask. And maybe even: what is a VJ? Wikipedia defines the characteristics of VJing as:

首先,什么是VJ引擎? 你可能会问。 甚至甚至:什么是VJ? 维基百科将VJing的特征定义为:

The creation or manipulation of imagery in realtime through technological mediation and for an audience, in synchronization to music.
通过技术中介实时创建或操纵图像,并与听众同步地为观众提供图像。

And a VJ engine is simply the software used for VJing.

VJ引擎只是用于VJing的软件。

But why would I build my own when there are so many VJ engines out there?

但是,当有如此多的VJ引擎出现时,为什么我要构建自己的引擎?

I never really loved VJ software — they always felt bloated and made everyone’s stuff look kinda the same. It’s kind of like when you first got your hands on Photoshop, and just blended a bunch of stuff together, added some filters, and it was cool (because it was the 90s). But most of all, I wanted tighter and better integration between developing content and the sound input frequencies.

我从未真正喜欢过VJ软件-他们总是感到felt肿,并使每个人的东西看起来都差不多。 这有点像您第一次接触Photoshop时,只是将一堆东西混合在一起,添加了一些滤镜,而且很酷(因为那是90年代)。 但最重要的是,我希望在开发内容和声音输入频率之间实现更紧密,更好的集成。

I rarely VJ these days, but it still drives most of my installations and performances — anywhere I need multiple visualisations I use RBVJ (the RB is for Radarboy — that’s me) as a wrapper/player.

这些天我很少使用VJ,但是它仍然可以驱动我的大多数装置和性能-在需要多幅可视化效果的任何地方,我都将RBVJ ( RB用于Radarboy ,就是我)用作包装器/播放器。

RBVJ has gone through a number of iterations over the years, as I’ve bounced from Flash, to Processing, and finally now to JavaScript, all using the same simple system.

多年来,RBVJ经历了多次迭代,正如我从Flash到处理,再到现在是JavaScript一样,都使用相同的简单系统。

I had previously open sourced it and my content (before the days of Git and not really knowing there was a thing called open-source). It won a bunch of awards, and I saw my content being used in a whole bunch of places which was nice. So I thought it was time to make it available for others again, along with a bunch of content to show how I go about creative coding.

我以前曾开源过它和我的内容(在Git出现之前,还不真正知道有一种叫做开源的东西)。 它赢得了很多奖项,我看到我的内容在很多地方都得到了很好的使用 。 因此,我认为是时候再次将其提供给其他人,以及一堆内容来展示我如何进行创意编码。

Ok, that’s a long enough introduction. Show me the money, you say!

好的,这是足够长的介绍。 你给我看看钱!

1.结构化内容 (1. Structuring the Content)

Essentially, a VJ engine is just a fancy content browser and player. So what we really need is a way to retrieve and play our content.

本质上,VJ引擎只是精美的内容浏览器和播放器。 因此,我们真正需要的是一种检索和播放内容的方法。

You could just dump all your content in a folder, but this system is what has worked best for me, allowing a simple structure for keyboard control:

您可以将所有内容转储到一个文件夹中,但是这个系统对我来说是最有效的,它提供了一种简单的键盘控制结构:

  • Shift 0–9 to change sets

    移0–9更改设置

  • Keys 0–9 to change banks

    0–9键更改银行

  • Keys a-z to choose content within the bank.

    按键az选择银行中的内容

This gives you 2,700 files to work with. If you really (really!?) wanted more, you could also double that by accessing another 26 files per bank with shift A-Z).

这样您就可以使用2,700个文件。 如果您真的(真的!?)想要更多,您还可以通过按AZ移位访问每个库中的另外26个文件来将其加倍。

Like most HTML projects, I have a simple top-level structure, and keep the VJ content in a numbered structure inside the art folder, like so:

像大多数HTML项目一样,我有一个简单的顶层结构,并将VJ内容保留在art文件夹内的编号结构中,如下所示:

index.html/css/js/art <- content goes here

My content folder (/art) contains 10 numbered folders, which I refer to as sets. Inside each set are another 10 numbered folders representing banks. And inside each bank are 27 individual numbered content files, like so:

我的内容文件夹(/ art)包含10个编号的文件夹,我称之为set 。 在每组里面还有另外10个编号编号的文件夹,代表银行 。 每个银行内有27个单独编号的内容文件,如下所示:

2.检索和播放内容 (2. Retrieving and Playing the Content)

Now we just need a way to access our files, which is done by injecting content into our index page.

现在,我们只需要一种访问文件的方式即可,方法是将内容注入到索引页面中。

And it’s pretty simple to do this.

做到这一点很简单。

The magic happens in a function called I’ve loadJS(). It creates a script tag within the page’s head and then injects some JavaScript into it (which would be our content). We trigger this function via a keypress (but could also be a midi or OSC signal) and pass the filename of the content we want into it. Then the script is available on the page.

神奇的事情发生在一个名为我的loadJS()函数中 它在页面的头部内创建一个脚本标签,然后向其中注入一些JavaScript(这将是我们的内容)。 我们通过按键触发该功能(但也可以是midi或OSC信号),然后将所需内容的文件名传递给它。 然后该脚本在页面上可用。

// INJECT JS ONTO PAGE
var my_script;
function loadJS(filename) {
// delete injected JavaScript if there’s been some loaded in before if (my_script != undefined)   document.getElementsByTagName("head")[0].removeChild(my_script);
// create a script element my_script = document.createElement(’script’); my_script.setAttribute("type", "text/javascript");
// Load the file in and insert it into the page’s head tag my_script.setAttribute("src", filename); document.getElementsByTagName("head")[0].appendChild(my_script);
}

We listen for keypresses with an event listener, which calls a function called onKeyDown(), like so:

我们使用事件侦听器侦听按键,该事件侦听器调用名为onKeyDown()的函数如下所示:

window.addEventListener( ’keydown’, function( event ) {   onKeyDown( event ); });

The listener passes the event object to the function, which contains a bunch of useful stuff. Here what we’re interested in: the event.keycode. Pressing the ‘a’ key gives us a keycode of 65, and pressing us a ‘z’ gives us a keycode of 90. So we simply subtract 65 from the keycode to give us the required file number and pass this value into a changeFile() function, which I’ll show in a bit.

侦听器将事件对象传递给函数,该函数包含一堆有用的东西。 这是我们感兴趣的: event.keycode 。 按“ a”键给我们键码为65,按“ z”给我们键码为90。所以我们只需从键码中减去65 给我们所需的文件编号 并将此值传递到changeFile()函数中,我将稍后显示。

Similarly we want keys 0–9 (keycodes 48 to 57, so subtract 48 ) to change banks. We also want test to see whether the shift key has been pressed to load sets. The event object has a handy event.shiftKey variable for this, so our onKeyDown function will look like so:

同样,我们希望键0–9(键代码48至57,所以减去48)来更改库。 我们还希望进行测试,以查看是否已按下Shift键来加载集合。 事件对象为此具有一个方便的event.shiftKey变量,因此我们的onKeyDown函数将如下所示:

// KeyPress Stuff
function onKeyDown( event ) {
var keyCode = event.keyCode;
// CHANGE FILE // keys a-z   if ( keyCode >= 65 && keyCode <= 90 ) {      changeFile(keyCode - 65);
// CHANGE SET AND BANK // keys 0-9   } else if ( keyCode >= 48 && keyCode <= 57 ) {
// Test whether the shift key is also being pressed      if( event.shiftKey ) {       changeBank( keyCode-48 );      } else {       changeSet( keyCode-48 );      }
}
}

The changeFile() function basically just takes the keypress and converts it into a URL. It calls our loadJS() function to inject the content into the page, and boom we’re away...

changeFile()函数基本上只需要按下按键并将其转换为URL。 它调用我们的loadJS()函数将内容注入页面,然后我们就离开了……

So our changeFile() function would look like this:

因此,我们的changeFile()函数将如下所示:

var current_file = 0;var current_set = 0;var current_bank = 0;
var art_location = "art/";
// FILE LOADER FUNCTIONS
function changeFile(file) {
current_file = file;  var loc = current_set + '/' + current_bank + '/' + current_file;  var filename = contentLocation + loc + '.js';  loadJS(filename);  document.location.hash = loc; //console.log("File: " + loc);
}

I also have an art_location variable in case I want to have different collections of visuals (so I can have different folders for different shows and installations). I also add the filename as a hash (https://127.0.0.1/#set/bank/file) to the browser’s URL to make it easy to see where I am.

如果我想拥有不同的视觉效果,我也有一个art_location变量(因此我可以为不同的演出和安装使用不同的文件夹)。 我还将文件名作为哈希(https://127.0.0.1/#set/bank/file)添加到浏览器的URL中,以方便查看我的位置。

Our changeBank() and changeSet() functions set the current_bank and current_set variables. Then they just call the changeFile() function to pull up the correct file.

我们的changeBank() changeSet()函数设置current_bankcurrent_set变量。 然后,他们只需调用changeFile()函数即可提取正确的文件。

For housekeeping, I also reset all the counters — setting current_file back to 0 when I change banks, and the current_bank back to 0 when I change sets. This is so I know that when I change banks, the file playing will be the first file in the bank. Similarly, when I change sets, the file playing will reset to be be the first file from the first bank of the current set (current_set/0/0.js).

为了看家,我也重置所有计数器-设置current_file回0当我改变银行和current_bank回到0当我改变集。 因此,我知道当我更换库时 ,正在播放的文件将是库中的第一个文件。 同样,当我更改集合时,正在播放的文件将重置为当前集合( current_set / 0 / 0.js )的第一个库中的第一个文件。

A bit of a mouthful, but the functions are actually super simple:

有点麻烦,但是功能实际上非常简单:

function changeSet(set) {
current_set = set;  console.log("changeSet: " + current_set);
// reset bank number  changeBank(0);
}
function changeBank(bank) {
current_bank = bank;  console.log("changeBank: " + current_bank);
// reset file number and load new file  changeFile(0);
}

And so the complete code for your basic VJ engine looks like this:

因此,基本VJ引擎的完整代码如下所示:

// FILE LOADER FUNCTIONS
var art_location = "/art";
var fileref;var current_file = 0;var current_set = 0;var current_bank = 0;
function changeFile( file ) {  reset()  current_file = file;  var loc = current_set + '/' + current_bank + '/' + current_file;  var filename = 'art/' + loc + '.js';  loadJS( filename );  document.location.hash = loc;  //console.log("File: " + loc);}
function changeSet( set ) {  current_set = set;  current_bank = 0;  console.log( "changeSet: " + current_bank );  // reset  changeFile( 0 );}
function changeBank( bank ) {  current_bank = bank;  console.log( "changeBank: " + current_bank );  changeFile( 0 );}
function reset(){  ctx.clearRect( 0, 0, w, h );  ctx2.clearRect( 0, 0, w, h );  ctx3.clearRect( 0, 0, w, h );  ctx.lineCap = "butt";}
// INJECT JS ONTO PAGE
function loadJS( filename ) {
if ( fileref != undefined ) document.getElementsByTagName( "head" )[ 0 ].removeChild( fileref );  fileref = document.createElement( 'script' );  fileref.setAttribute( "type", "text/javascript" );  fileref.setAttribute( "src", filename );  document.getElementsByTagName( "head" )[ 0 ].appendChild( fileref );
}

All that’s left to show you is how I structure the actual content files, which use an encapsulated function like so:

剩下要向您展示的是我如何构造实际的内容文件,它们使用如下封装的函数:

// RBVJ art
rbvj = function() {
draw = function() {     // do some creative coding here  }
}();

The function rbvj() is what gets injected into the page. It’s reused, so that every time a new file is inserted into my page, the memory gets flushed from all previous content.

函数rbvj()是注入页面的内容。 它已被重用,因此每次将新文件插入我的页面时,都会从所有先前的内容中清除内存。

By encapsulating the code (see the ‘()’ after the function), any code inside the rbvj() function will run automatically when the file is injected into the page.

通过封装代码(请参见函数后的“()”), rbvj()中的任何代码 文件插入页面后,该功能将自动运行。

You’ll notice that inside the content, I have a draw() function (this one from my own creative_coding.js utility script). It’s just a simple loop that uses JavaScript’s requestAnimationFrame() and is able to vary the frame rate.

您会注意到,在内容内部,我有一个draw()函数(该函数来自我自己的creative_coding.js实用程序脚本)。 这只是一个使用JavaScript的requestAnimationFrame()的简单循环 并能够更改帧速率。

var frame_number = 0;var frame_rate = 60;var last_update = Date.now();
function loop() {
var now = Date.now();  var elapsed_mils = now - last_update;
if ((typeof window.draw == 'function') && (elapsed_mils >= (1000 / window.frame_rate))) {    window.draw();    frame_number++;    last_update = now - elapsed_mils % (1000 / window.frame_rate);  }  requestAnimationFrame(loop);
};

And that’s pretty much it. You now have a working VJ engine in the bowser.

就是这样。 现在,bower中的VJ引擎正在运行。

3.其他一些可能会有所帮助的事情 (3. Some other things to know that may be helpful)

I normally just plug my computer’s sound input straight into an input from the venue’s mixer or amp (I use a version of my standard microphone input mic.js file, which you can read more about here). And I have keys setup (in my case, the plus and minus keys) to adjust the input levels up or down, so I don’t have to keep accessing the mixer.

通常,我通常只是将计算机的声音输入直接插入场地调音台或放大器的输入中(我使用标准麦克风输入mic.js文件的版本,您可以在此处了解更多信息)。 而且我有按键设置(在我的情况下,是加号减号 )可以向上或向下调整输入电平,因此我不必一直访问调音台。

Also note that for sound input, you’ll need a secure HTTPS connection — or if you use something like Atom’s Live Server, then that’s built in.

还要注意,对于声音输入,您将需要一个安全的HTTPS连接-或如果使用诸如Atom的Live Server之类的东西,那么它是内置的。

I also have a bunch of other keys set up for simple audio and visual filters (see how to make a pixelation filter here).

我还为简单的音频和视觉过滤器设置了许多其他键(请参阅此处如何制作像素化过滤器)。

I mostly don’t use a preview screen/interface, but it’s easy enough to build one. Just create a new HTML page and let the pages talk to each other through a socket.

我通常不使用预览屏幕/界面,但是构建一个界面很容易。 只需创建一个新HTML页面,然后让这些页面通过套接字彼此对话即可。

And finally, one last tip: when developing content, simply make a function to read in the current hash value of the browser, and call the loadFile() function on page load. That way, when you’re working on a file and you reload the page, that file is automatically displayed.

最后,最后一个技巧是:开发内容时,只需编写一个函数以读取浏览器的当前哈希值,然后在页面加载时调用loadFile()函数。 这样,当您处理文件并重新加载页面时,该文件将自动显示。

And that’s pretty much it. Hope this helps you get out there and show more of your content. As I mentioned previously, I’ve included a whole bunch of content for you to play around with and test so you can get a feel of how I create my stuff. If you use or alter any of it, I’d love to see how, where, and what you did with it. So please drop me a line.

就是这样。 希望这可以帮助您走到那里,并显示更多内容。 如前所述,我提供了很多内容供您试用和测试,以便您能体会到我如何创建自己的东西。 如果您使用或更改了其中任何一个,我很乐意了解您如何,在何处以及如何使用它。 所以请给我打个电话。

Happy coding. And thanks for reading!

快乐的编码。 并感谢您的阅读!

As usual the full code is available on Github.

和往常一样,完整的代码可以在Github上找到

This article is part of an ongoing series of tutorials on learning creative coding in pure JavaScript. As yes, I should be doing this in ES6, but wanted to keep this as simple as possible to understand.

本文是有关使用纯JavaScript学习创意编码的一系列教程的一部分。 是的,我应该在ES6中进行此操作,但希望保持其尽可能的简单易懂。

You can see previous all my previous creative coding tutorials here.

您可以在这里查看我之前所有的创意编码教程。

And follow me here for updates, techniques and eye candy:

并在这里关注我,以获取更新,技巧和眼神:

@radarboy3000 * Instagram photos and videos3,960 Followers, 843 Following, 1,082 Posts - See Instagram photos and videos from @radarboy3000www.instagram.comGeorge Gally (@radarboy_japan) | TwitterThe latest Tweets from George Gally (@radarboy_japan). Media artist, technologist, tinkerer, dreamer. Motion reaction…twitter.comRadarboyRadarboy. 130 likes · 7 talking about this. Art, design visualisation, hackswww.facebook.com

@ radarboy3000 * Instagram照片和视频 3,960关注者,843以下,1,082帖子-查看@ radarboy3000的Instagram照片和视频 www.instagram.com George Gally(@radarboy_japan)| Twitter 来自George Gally的最新推文(@radarboy_japan)。 媒体艺术家,技术专家,修补匠,梦想家。 运动React… twitter.com Radarboy Radarboy。 130喜欢·7谈论这个。 艺术,设计可视化,黑客攻击 www.facebook.com

翻译自: https://www.freecodecamp.org/news/how-to-create-a-vj-engine-in-javascript-b63b7fb1c87b/

vj节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值