
Записка_к_курсачу
.pdf
Рисунок 5.6 - Страница с плеером
При нажатии на картинку нужной песни начинается загрузка файла, о чѐм уведомляет подсказка в правом углу. По завершении загрузки подсказка уведомит, что файл загружен и готов к воспроизведению.
Когда начинается воспроизведение, пользователь в реальном времени может видеть визуализированный вариант песниспектр частот, описывающих еѐ(рис 5.7)
21

Рисунок 5.7 - Воспроизведение
22
ЗАКЛЮЧЕНИЕ
Вкурсовом проекте проведен анализ и даны прогнозы развития web audio api. Разработано программное средство, демонстрирующее возможности данной технологии. Данная программа предоставляет возможность ознакомиться с web audio, а также может служить хранилищем медиафайлов.
Впроцессе работы над курсовым проектом я познакомился с функциями web audio. Более глубоко усвоил написание прототипов на javascript.
23
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
[1]O’Reilly, Р. Javascript: подробное руководство(the definitive guide) / O’Reilly - СПб.: Питер, 2004. - 928 с.
[2]Википедия [Электронный ресурс]. - Электронные данные. - Режим доступа: http://ru.wikipedia.org/wiki/
[3]Флэнаган, Д. Язык программирования Ruby / Д. Флэнаган,Ю. Мацумото. - Питер, 2011.
[4]Шаблон проектирования ActiveRecord [Электронный ресурс]. - Электронные данные. - Режим доступа: ttps://github.com/rails/rails/tree/master/activerecord
[5]Краткая экскурсия по языку Ruby - СПб.: Питер, 2007. - 196 с. - ISBN 5- 469-01291-3.
[6]Yukihiro Matsumoto. Ruby in a Nutshell - Sebastopol, CA: O’Reilly, 2002.
-ISBN 0-596-00214-9.
[7]Фицджеральд М. Изучаем Ruby (Learning Ruby) - 1-е изд. - СПб.: BHV-
СПб, 2008. - 336 с. - ISBN 978-5-9775-0225-2
[8]The Ruby Way - 2-е изд. - М.: ДМК Пресс, 2007. - 688 с. - ISBN 0-672- 32884-4.
[9]Тейт Б., Хиббс К. Ruby on Rails. Быстрая веб-разработка - СПб.: BHVПетербург, 2008. - 224 с.
[10]StackOverflow [Электронный ресурс]. - Электронные данные. - Режим
доступа: http://stackoverflow.com/
24
ПРИЛОЖЕНИЕ A Исходный код программы
source 'https://rubygems.org' gem 'rails', '4.0.3'
gem 'sass-rails', '~> 4.0.0' gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0' gem 'haml'
gem 'devise' gem 'mysql2'
gem 'jquery-rails' gem 'turbolinks'
gem 'jbuilder', '~> 1.2' gem 'bootstrap-sass'
gem 'bootstrap-slider-rails' gem 'pg'
gem 'font-awesome-rails' gem 'paperclip', "~> 3.5.3"
gem 'rails_12factor', group: :production gem 'simple_form'
gem 'remotipart' group :development do
gem 'pry'
gem 'proxylocal'
gem 'better_errors'
end
group :doc do
gem 'sdoc', require: false
end
class Song < ActiveRecord::Base belongs_to :user
validates :title, presence: true has_attached_file :track
validates_attachment_content_type :track,
:content_type => ['application/ogg','audio/mp3', 'application/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/ogg'],
:file_name => { :matches => [/mp3|ogg\Z/]} do_not_validate_attachment_file_type :track
end
class User < ActiveRecord::Base
#Include default devise modules. Others available are:
#:confirmable, :lockable, :timeoutable and :omniauthable has_many :songs
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
end
25
class AudioController < ApplicationController def index
@song = Song.new
@songs = current_user.songs; end
def create
@song = Song.new(song_params) @song.user = current_user respond_to do |format|
if @song.save format.js
end end
end
private
def song_params
params.require(:song).permit(:title, :performer, :track) end
end
class StaticController < ApplicationController def index
end end
BloudAudiotools::Application.routes.draw do get "static/index"
devise_for :users
root 'static#index'
resources :audio, only: [:index, :create]
#Example of regular route:
#get 'products/:id' => 'catalog#view'
#Example of named route that can be invoked with purchase_url(id: product.id)
#get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
end
function bloudPiano() { this.sampleRate = 44100; this.mNumNotes = 32 + 12*2;
this.noteSamples = new Array(this.mNumNotes); this.noteLen = 1*this.sampleRate;
this.buffer = null; this.octave = 0; this.volume = 100; var self = this; $(".slider").slider({
26
'min': "0", 'max': "100", 'value': "100", 'step': "2",
'orientation': 'horizontal' }).on('slide', function(ev) {
self.volume = ev.value;
})
this.formulaArea = document.getElementById("formulas"); this.mAudioContext = null;
this.mCanvasGraph = null;
this.mCanvasGraph = document.getElementById("graph"); this.mCanvasPiano = document.getElementById("piano");
if( window.AudioContext ) { this.mAudioContext = new AudioContext(); } if( this.mAudioContext==null ) {
if( window.webkitAudioContext ) { this.mAudioContext = new webkitAudioContext();
}
}
if( this.mAudioContext==null ) {
alert("your browser doesn't support AudioContext, update it") return;
}
this.buffer = new Array( 8 ); this.mActiveNote = new Array( 8 ); for( j=0; j<8; j++ )
{
this.buffer[j] = this.mAudioContext.createBuffer( 1, this.noteLen, this.sampleRate );
this.mActiveNote[j] = { mNote:666, mTo:0.0 };
}
for( j=0; j<this.mNumNotes; j++ )
{
this.noteSamples[j] = new Float32Array(this.noteLen);
}
this.mId = 0;
this.formulaArea.value = "y = sin(w*t)*exp(-5*t);"; this.newSound();
}
bloudPiano.prototype.newSound = function()
{
var self = this;
var message = "Done";
var formula = this.formulaArea.value; try
{
var musPattern = new String(formula);
musPattern = musPattern.replace( /sin/gi, "Math.sin" ); musPattern = musPattern.replace( /cos/gi, "Math.cos" ); musPattern = musPattern.replace( /tan/gi, "Math.tan" ); musPattern = musPattern.replace( /asin/gi, "Math.asin" ); musPattern = musPattern.replace( /acos/gi, "Math.acos" );
27
musPattern = musPattern.replace( /exp/gi, "Math.exp" ); musPattern = musPattern.replace( /pow/gi, "Math.pow" ); musPattern = musPattern.replace( /sqrt/gi, "Math.sqrt" ); musPattern = musPattern.replace( /log/gi, "Math.log" ); musPattern = musPattern.replace( /abs/gi, "Math.abs" ); musPattern = musPattern.replace( /min/gi, "Math.min" ); musPattern = musPattern.replace( /max/gi, "Math.max" ); musPattern = musPattern.replace( /round/gi, "Math.round" ); musPattern = musPattern.replace( /floor/gi, "Math.floor" ); musPattern = musPattern.replace( /ceil/gi, "Math.ceil" ); musPattern = musPattern.replace( /random/gi, "Math.random" );
var func = new Function( "w", "num", "buf", "var isr = 1.0/44100.0; for( i=0; i<num; i++ ) { var t = i*isr; var y=0.0; " + musPattern + "; buf[i] = y; }" );
var noteIndex = 0;
function calcFrequencies() {
if(noteIndex >= self.mNumNotes) return;
var f = 440.0*Math.pow( 2.0, (noteIndex-12-9)/12.0 ); var w = 2.0*Math.PI*f; func(w,self.noteLen,self.noteSamples[noteIndex]); noteIndex = noteIndex + 1;
calcFrequencies();
}
noteIndex = 0; calcFrequencies();
this.drawGraph();
}
catch(e) { message = e;
}
console.log(message);
}
bloudPiano.prototype.playNote = function( note ) { var id = this.mId;
note += this.octave*12;
this.mId = (this.mId+1) % 8;
var dbuf = this.buffer[id].getChannelData(0); var num = this.noteLen;
var sbuf = this.noteSamples[note]; for( i=0; i<num; i++ )
{
dbuf[i] = sbuf[i];
}
var gainNode = this.mAudioContext.createGain(); gainNode.connect(this.mAudioContext.destination); gainNode.gain.value = 0.5 * this.volume/100.0;
var node = this.mAudioContext.createBufferSource();
28
node.buffer = this.buffer[id]; gainNode.gain.value = 0.5 * this.volume/100.0; gainNode.connect(this.mAudioContext.destination); node.connect(gainNode);
node.state = node.noteOn; node.start(0);
this.mActiveNote[id].mNote = note; this.mActiveNote[id].mTo = new Date().getTime();
}
bloudPiano.prototype.drawGraph = function() { var ctx = this.mCanvasGraph.getContext('2d');
var xres = this.mCanvasGraph.width; var yres = this.mCanvasGraph.height;
ctx.fillStyle = '#202020'; ctx.fillRect(0, 0, xres, yres);
ctx.strokeStyle = '#596DFF'; ctx.lineWidth = 1;
ctx.beginPath();
for(var |
i = 0; i < this.noteLen; i++) { |
|
var x |
= xres*i/this.noteLen; |
|
var y |
= this.noteSamples[0][i]; |
|
var j |
= yres*(0.5+0.5*y); |
|
ctx.lineTo(x, j); |
|
|
} |
|
|
ctx.stroke(); |
|
|
ctx.closePath(); |
|
|
} |
|
|
bloudPiano.prototype.setVolume = function() |
|
|
{ |
|
|
var v = |
document.getElementById("myVolume").value; |
|
if( v< |
0 ) { v= 0; document.getElementById("myVolume").value = |
0; } |
if( v>100 ) { v=100; document.getElementById("myVolume").value = 100; } this.volume = v;
}
$(document).ready(function(){ var piano = null;
if (document.querySelector("#graph")) initPiano();
})
function initPiano() { piano = new bloudPiano();
window.onkeydown = function(ev)
{
if(piano ==null)
piano = new bloudPiano();
29
var note = 666; |
|
|
|
//----------------------------------- |
|
|
|
if( |
ev.keyCode==90 |
) |
note= 0; // C 0 |
if( |
ev.keyCode==83 |
) |
note= 1; // C#0 |
if( |
ev.keyCode==88 |
) |
note= 2; // D 0 |
if( |
ev.keyCode==68 |
) |
note= 3; // D#0 |
if( |
ev.keyCode==67 |
) |
note= 4; // E 0 |
if( |
ev.keyCode==86 |
) |
note= 5; // F 0 |
if( |
ev.keyCode==71 |
) |
note= 6; // F#0 |
if( |
ev.keyCode==66 |
) |
note= 7; // G 0 |
if( |
ev.keyCode==72 |
) |
note= 8; // G#0 |
if( |
ev.keyCode==78 |
) |
note= 9; // A 0 |
if( |
ev.keyCode==74 |
) |
note=10; // A#0 |
if( |
ev.keyCode==77 |
) |
note=11; // B 0 |
//----------------------------------- |
|
|
|
if( |
ev.keyCode==81 |
) |
note=12; // C 1 |
if( |
ev.keyCode==50 |
) |
note=13; // C#1 |
if( |
ev.keyCode==87 |
) |
note=14; // D 1 |
if( |
ev.keyCode==51 |
) |
note=15; // D#1 |
if( |
ev.keyCode==69 |
) |
note=16; // E 1 |
if( |
ev.keyCode==82 |
) |
note=17; // F 1 |
if( |
ev.keyCode==53 |
) |
note=18; // F#1 |
if( |
ev.keyCode==84 |
) |
note=19; // G 1 |
if( |
ev.keyCode==54 |
) |
note=20; // G#1 |
if( |
ev.keyCode==89 |
) |
note=21; // A 1 |
if( |
ev.keyCode==55 |
) |
note=22; // A#1 |
if( |
ev.keyCode==85 |
) |
note=23; // B 1 |
//----------------------------------- |
|
|
|
if( ev.keyCode==73 ) |
|
note=24; // C 2 |
|
if( |
ev.keyCode==57 |
) |
note=25; // C#2 |
if( ev.keyCode==79 ) |
|
note=26; // D 2 |
|
if( |
ev.keyCode==48 |
) |
note=27; // D#2 |
if( ev.keyCode==80 ) |
|
note=28; // E 2 |
|
if( |
ev.keyCode==219 ) |
note=29; // F 2 |
|
if( |
ev.keyCode==187 ) |
note=30; // F#2 |
|
if( |
ev.keyCode==221 ) |
note=31; // G 2 |
|
//----------------------------------- |
|
|
|
if( note==666 ) return; |
|
||
piano.playNote( note |
); |
|
}
}
BLoudPlayer = (function (){ BLoudPlayer = function() {
var self = this;
this.context = new AudioContext(); this.destination = this.context.destination; this.buffer = null;
this.state = "idle"; this.setupGraphics(); this.setupAudioNodes();
Array.prototype.forEach.call(document.querySelectorAll('.audiofile'),
function(e){
e.addEventListener('click', function(){
30