2014年12月28日日曜日
RixMini.java の ソースコード
/*
▼RixMini 仕様
再生・停止のPlayButtonと、T,S,Dの order を入力するCadenceButtonを実装。
CadenceButtonを操作して和声進行を演奏する。
何も入力せずに次の小節に行くと、HarmonyBalancerが作動して、最適なバランス値をもたらす和声を演奏する。
和声進行のバランス値に応じてグラデーションで色が変わる楕円 class Graph を実装。
和声進行のバランス値と、4声コードの内容(12音表記)と、入力した cadenceOrderList を、リアルタイムで表示するパネル class Display を実装。
実装クラス一覧:
{ RixMini, Graph, Display, ButtonPanel, Conductor, Harmony, Key, EqualKey, Scale, HarmonyBalancer, Rhythm, Dynamics, Meter, Sound, Sine, PercussiveNoise }
*/
class RixMini extends JFrame { // BAK 2014.11.10
int frameWidth = 320;
int frameHeight = 480;
Color backColor = new Color(245, 150, 20);
static Display display = new Display();
static Graph graph = new Graph();
static ButtonPanel buttonPanel = new ButtonPanel();
int marginLeft = 5; // setResizable(true)のときと(false)のときの左余白の差の調整
// static boolean statePlaying = false;
public static void main(String[] args) {
// Sine s = new Sine(800,1000,800);
// Thread t = new Thread(s);
// t.start();
Conductor.init();
new RixMini().setVisible(true);
}
public RixMini() {
super();
setTitle("RixMini");
setSize(frameWidth, frameHeight); // スマホ用サイズに変更させる
setLocationRelativeTo(null); // 画面中央に表示
setLayout(null);
setResizable(false);
getContentPane().setBackground(backColor);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// logo
JLabel logo = new JLabel("RixMini");
logo.setBounds(10,10,120,24);
// logo.setBorder(new LineBorder(Color.BLACK));
logo.setFont(new Font("Serif",Font.PLAIN,22));
logo.setForeground(new Color(120,20,20));
this.add(logo);
// graph
graph.setBounds(20+marginLeft, 46, 262, 146);
// graph.setBorder(new LineBorder(Color.RED));
this.add(graph);
// display
display.setBounds(40+marginLeft, 190, 262, 100);
// display.setBorder(new LineBorder(new Color(120,20,20)));
display.setBackground(backColor);
this.add(display);
// buttonPanel
buttonPanel.setBounds(46+marginLeft, 304, 208, 128);
this.add(buttonPanel);
}
} // class RixMini
class Graph extends JPanel { // BAK 2014.11.10
/*
class Graph 説明
Balancerの値を利用してユーザーに視覚効果を与えて楽しませるクラス。
機能
・Balancer.harmonyRecord の値によって背景色がグラデーションで変わる
*/
static int[] h = new int[4];
/* 以下の3つの配列は、試験的に、前から2つの要素までしか使わない。 */
static int[] hR = new int[4]; // h から赤色成分だけ抽出 Dominantへの近さ
static int[] hG = new int[4]; // h から緑色成分だけ抽出 Tonic(0)への近さ
static int[] hB = new int[4]; // h から青色成分だけ抽出 Subdominantへの近さ
static int nowR;
static int nowG;
static int nowB;
static int frame = 24;
public Graph(){
}
public void update() {
for (int i = 0; i < HarmonyBalancer.harmonyRecord.length; i++) {
// System.out.println("Graph.update() harmonyRecord : " +Conductor.conductor.harmony.balancer.harmonyRecord[i] * 255 / 1000 );
h[i] = Conductor.conductor.harmony.balancer.harmonyRecord[i] * 255 / 1000 ; //色の比率に変更.
if (h[i] >= 0) {
//System.out.println("ThroughFlag : Graph.update() ifBlock");
hR[i] = h[i];
hG[i] = 255 - h[i];
} else {
//System.out.println("ThroughFlag : Graph.update() elseBlock");
hB[i] = h[i] * -1;
hG[i] = 255 + h[i];
}
}
ColorMotion cm = new ColorMotion();
Thread colorThread = new Thread(cm);
colorThread.start();
}
@Override
public void paint(Graphics g) { // paint()はJPanel描画の度に呼ばれるメソッド.
// super.paint(g);
// g.drawRect(0, 0, 862, 526);
Graphics2D g2 = (Graphics2D) g; // 機能が豊富なGraphics2D にキャスト
// System.out.println(" hR = "+hR[1] + " hG = "+ hG[1] + " hB = "+hB[1]);
GradientPaint gp = new GradientPaint(0, 0, new Color(hR[1], hG[1], hB[1]), 100, 10, new Color(nowR, nowG, nowB), true);
g2.setPaint(gp);
Ellipse2D ellipse = new Ellipse2D.Double(10, 0, 242, 130); // Ellipse2Dは楕円描画.
g2.fill(ellipse);
g.setColor(new Color(151, 151, 111));
}
class ColorMotion implements Runnable {
public void run() {
try {
for (int i = 0; i < frame; i++) {
nowR = hR[1] + (hR[0] - hR[1]) / frame * i;
nowG = hG[1] + (hG[0] - hG[1]) / frame * i;
nowB = hB[1] + (hB[0] - hB[1]) / frame * i;
repaint(); // 描画の更新
}
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(RixMini.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
} // class Graph
class Display extends JPanel { // BAK 2014.11.10
/* class Display
RixMiniの内部情報をテキストで表示するPanel。
機能
・Conductor.cadenceOrderListを表示
・Harmony.chord[] を表示
・HarmonyBalancer.harmonyRecord を表示
*/
String chord;
String harmonyBalance;
JLabel orderLabel = new JLabel("order | ");
JLabel chordLabel = new JLabel("chord | ");
JLabel harmonyBalanceLabel = new JLabel("balance | ");
public Display() {
setLayout(new GridLayout(3, 1));
// harmonyBalanceLabel.setBounds(0, 40, 100, 10);
harmonyBalanceLabel.setFont(new Font("Serif", Font.PLAIN, 16));
harmonyBalanceLabel.setForeground(new Color(30, 20, 50));
this.add(harmonyBalanceLabel);
// chordLabel.setBounds(0, 20, 100, 10);
chordLabel.setFont(new Font("Serif", Font.PLAIN, 16));
chordLabel.setForeground(new Color(20, 40, 20));
this.add(chordLabel);
orderLabel.setFont(new Font("Serif", Font.PLAIN, 18));
orderLabel.setForeground(new Color(120, 20, 20));
// orderLabel.setBorder(new LineBorder(new Color(120,20,20)));
// orderLabel.setBounds(0, 0, 100, 10);
this.add(orderLabel);
}
public void updateOrder() {
orderLabel.setText("order | "+Conductor.conductor.cadenceOrderList.toString());
}
public void updateHarmonyInfo() {
chord = "chord | ";
for (int c : Conductor.conductor.harmony.chord) {
chord += Integer.toString(c) + " ";
}
chordLabel.setText(chord);
harmonyBalance = "balance | ";
for (int b : Conductor.conductor.harmony.balancer.harmonyRecord) {
harmonyBalance += Integer.toString(b) + " ";
}
harmonyBalanceLabel.setText(harmonyBalance);
}
} // class Display
class ButtonPanel extends JPanel { // BAK 2014.11.10
PlayButton playBtn = new PlayButton();
CadenceButton tBtn = new CadenceButton("T");
CadenceButton dBtn = new CadenceButton("D");
CadenceButton sBtn = new CadenceButton("S");
public ButtonPanel() {
setLayout(new GridLayout(2, 2));
add(tBtn);
add(dBtn);
add(playBtn);
add(sBtn);
}
class PlayButton extends JButton {
String btnMark[] = {" > ", " || "};
public PlayButton() {
setText(btnMark[0]);
setFont(new Font("Serif",Font.PLAIN,22));
this.addActionListener(new ClickReaction());
}
public class ClickReaction implements ActionListener {
@Override
public void actionPerformed(ActionEvent ev) {
try {
if (Conductor.statePlaying == false) {
Thread conductorThread = new Thread(Conductor.conductor);
conductorThread.start();
setText(btnMark[1]);
} else {
Conductor.conductor.stop();
setText(btnMark[0]);
}
} catch (Exception ex) {
//System.out.println(ex);
// ex.printStackTrace();
ex.printStackTrace(System.out);
}
}
}
public void changeMark() {
if (Conductor.statePlaying) {
//System.out.println("Through Flag : playBtn.changeMark() ifBlock");
setText(btnMark[1]);
} else {
//System.out.println("Through Flag : playBtn.changeMark() elseBlock");
setText(btnMark[0]);
}
}
} // class PlayButton
class CadenceButton extends JButton {
boolean statePlaying = false;
String btnMark[] = {"T", "S", "D"};
String btnName;
public CadenceButton(String funcName) {
this.btnName = funcName;
setText(btnName);
setFont(new Font("Serif", Font.PLAIN, 22));
this.addActionListener(new ClickReaction());
}
public class ClickReaction implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
Conductor.cadenceOrderList.append(btnName);
RixMini.display.updateOrder();
} catch (Exception ex) {
System.out.println("myERROR: ClickBtn.actionPerformed ");
}
}
}
} // class CadenceButton
} // class ButtonPanel
public class Conductor implements Runnable { // BAK 2014.11.10
static Conductor conductor;
public static boolean statePlaying;
public static StringBuilder cadenceOrderList;
static Harmony harmony;
static Rhythm rhythm;
static Score score;
public Conductor() {
statePlaying = false;
cadenceOrderList = new StringBuilder();
harmony = new Harmony();
rhythm = new Rhythm();
}
public static void init() {
conductor = new Conductor();
}
public void run(){
score = new Score(8); // 引数は演奏小節数の総数
start();
}
public void start() {
statePlaying = true;
//System.out.println("statePlaying CHECK at start() : "+statePlaying);
conduct();
}
public void stop() {
//System.out.println("Through Flag : Conductor.stop()");
statePlaying = false;
RixMini.buttonPanel.playBtn.changeMark();
}
void orderReset(){
cadenceOrderList.delete(0,cadenceOrderList.length());
RixMini.display.updateOrder();
}
private void conduct() {
try {
Thread threadHarmony = new Thread((Runnable) harmony);
Thread threadRhythm = new Thread((Runnable) rhythm);
threadHarmony.start();
threadRhythm.start();
RixMini.display.updateHarmonyInfo();
RixMini.graph.update();
threadHarmony.join();
threadRhythm.join();
orderReset();
score.look();
// System.out.println("CHECK AT conduct() :"+statePlaying);
} catch (InterruptedException ex) {
Logger.getLogger(Conductor.class.getName()).log(Level.SEVERE, null, ex);
}
}
static class Score {
static int unplayBar;
boolean musicIsEnd;
public Score(int bar){
unplayBar = bar;
}
public void look(){
unplayBar--;
if(unplayBar > 0 ) {
//System.out.println("Through Flag : Score.look() ifBlock "+ unplayBar);
Conductor.conductor.conduct();
} else {
//System.out.println("Through Flag : Score.look() elseBlock "+ unplayBar);
musicIsEnd = true;
conductor.stop();
}
}
} // class Score
} // class Conductor
public class Harmony implements Runnable{ // BAK 2014.11.10
static Key key;
static Scale scale ;
static HarmonyBalancer balancer;
static int tonicPitch = 300;
static int tonicNum = 0; //機能和声番号は、配列と適合させるため -1 した番号とする。
static int pastFuncNum = 0;
static int[] chord;
static int chordOct = 4; // chord の音程のオクターブ数
static float chordVol = 500; // playChord の音量
public Harmony(){
key = new EqualKey(tonicPitch);
scale = new Scale(tonicNum, Scale.major);
chord = new int[]{0, 4, 7, 0xB};
balancer = new HarmonyBalancer(); // balancerの初期化はScaleの初期化を要するので
// 初期化の順序に注意すること。
}
@Override
public void run(){
symbol2Chord(Conductor.cadenceOrderList.toString());
playChord(chord);
RixMini.display.updateHarmonyInfo();
RixMini.graph.update();
Conductor.conductor.orderReset();
}
void init(){
scale.change(tonicNum, Scale.major);
chord = getChord(0);
HarmonyBalancer.harmonyRecord = new int[]{0,0,0,0};
pastFuncNum = 0;
tonicNum = 0;
}
public static int[] getChord ( int funcNum){
pastFuncNum = funcNum;
int[] c = new int[4];
int[] s = scale.getScale();
for( int i =0; i<4; i++){ // i<4 なのは 4声だから。
c[i] = s[ ( funcNum + i*2 ) % 7 ];
}
return c;
}
public void symbol2Chord ( String symbol ){
if(symbol.length() == 0){
symbol = symbol +"A";
}else {
Conductor.conductor.score.unplayBar +=1;
}
symbol = symbol + "E"; // 処理されない最終文字 E を追加
char[] symbolArray = symbol.toCharArray();
int funcNum = pastFuncNum;
/* Balancer が算出する値に応じて、switch文の内容を変化させる案もある。 */
for ( int i=0 ; i < symbolArray.length -1; i++ ) {
if(symbolArray[i]== symbolArray[i+1]){
switch (symbolArray[i]) {
case 'S':
if (scale.interval == Scale.major) {
scale.change(tonicNum += 9, Scale.minor); // la minor scale へ。
} else if (scale.interval == Scale.minor) {
scale.change(tonicNum += 3, Scale.major); // do major scale へ。
}
;
break;
case 'T':
scale.change(tonicNum += 6);
break;
case 'D':
scale.change(tonicNum += 7);
funcNum += 4;
break;
default:
System.out.println("Invalid kadenzSymbol at Harmony.symbol2Chord");
}
i++;
}else{
switch(symbolArray[i]){
case 'T': funcNum = 0 ; break; // TS、TDと入力することで、presentScale のSとDをいつでも呼び出せる。
case 'S': funcNum += 3; break;
case 'D': funcNum +=4; break;
case 'A': funcNum = balancer.getNextHarmony(pastFuncNum); break; // 何も入力されていないとき、Aが入る
default: System.out.println("Invalid kadenzSymbol at Harmony.symbol2Chord");
}
}
/* オクターブ移動のアルゴリズムは、未定なので、すべてのオクターブ番号を中心の4とする。
ボイシングを考えつつ機能拡張する必要あり。 */
// chordOct += funcNum / 7;
funcNum %= 7;
}
chord = getChord(funcNum);
HarmonyBalancer.recordHarmony(chord); // Balancerの変数に1小節前の和声として記録しておく。
}
public void playChord ( int[] chord ){
float freq;
for(int c : chord ){
freq = key.num2Hz(chordOct, c) ;
//System.out.println("CHECK playChord() " + freq +" "+ Rhythm.Meter.oneBar+" "+ chordVol );
Sound s = new Sine ( freq , Rhythm.Meter.oneBar, chordVol );
Thread t = new Thread(s);
t.start();
}
}
} // class Harmony
abstract class Key { // OK
int centerPitch ;
scaleArray [] = { } ;
octaveArray [] = { } ;
public Key (int c){
this.centerPitch = c ;
tuning();
}
public void tuning (){
}
public int num2Hz ( int oct , int num ) {
}
} // class Key
public class EqualKey extends Key { //OK
int centerPitch ;
scaleArray [] = { } ;
octaveArray [] = { } ;
public Key (int c){
this.centerPitch = c ;
tuning();
}
public void tuning (){
for (int i = 0; i<12 ; i++){
scaleArray[i] = tonicPitch * Math.pow(2.0 , i / 12.0 );
}
for ( int i = 0; i<8; i++ ){
octaveArray[i] = Math.pow( 2 , (i - 4 ) ) ;
}
}
public int num2Hz ( int oct , int num ) {
int hz = scaleArray[num] * octaveArray[oct];
return hz;
}
} // class EqualKey
class Scale { // OK
int[] presentScale ;
public int[] major = { 0 , 2 , 4, 5, 7, 9, B };
public int[] minor = { 0, 2 , 3 , 5 , 7 , 8 , A };
public int[] interval ;
int tonicNum ;
public Scale(int tonicNum , int[] interval ){
change( tonicNum, interval);
}
public int[] getScale(){
return presentScale;
}
public void change(int newTonicNum , int[] interval ){
for( int i=0; i<7; i++ ) {
presentScale[i] = (newTonicNum + interval[i] ) % 12 ;
}
}
public void change(int newTonic ){
this.change(newTonic, this.interval );
}
public void change(int[] interval ){
this.change(this.tonic, interval );
}
} //class Scale
class HarmonyBalancer { // OK
int[] harmonyRecord = new int[4] ; // 過去4小節分の cadenceValue が入る配列
int[] pastChord = new int[4]; // 1小節前の Chord 配列
int[][] cadenceValueTable; // Scale.presentScaleの和声進行が持つvalue値の表
/* 音程 0_0, 0_1, 0_2 ... の順で12音程分の value を含む配列 */
int[] intervalValueD_SD = { 0 , -50, 0, +50, 0, -100, 0, +100, 0, -50, 0, +50 };
public HarmonyBalancer(){
setCadenceValue();
}
public void recordHarmony(int[] chord){
int diffNum;
int cadenceValue;
if(pastChord == null ){
pastChord = chord;
}
for(int i =0; i<4; i++){
for(int j = 0; j<4 ; j++ ){
diffNum = chord[i] - pastChord[j] ;
cadenceValue += intervalValueD_SD[diffNum];
}
}
for( int i =0; i< harmonyRecord.length - 1 ; i++ ) {
harmonyRecord[i] = harmonyRecord[i+1]
}
harmonyRecord[harmonyRecord.length -1 ] = cadenceValue;
}
public int getNextHarmony(int pastFuncNum){ // 機能和声の番号を返す
int lean = 0;
int nextValue;
int optinumFuncNum;
int remainder;
int minDiff = 2000; // 2000 は cadenceValue の差の最大値(上下1000ずつ)
for(int i =0; i< harmonyRecord.length; i++ ){
lean += harmonyRecord[i];
}
nextValue = lean * -1 ; // harmonyRecord の value の偏りを揺り戻す
for(int i = 0; i< cadenceValueTable[pastFuncNum].length; i++){
remainder = cadenceValueTable[pastFuncNum][i] - nextValue;
if(remainder < 0 ) {
remainder *= -1; // 差を絶対値化
}
/*
まったく同じ値の remainder が算出されたときには、
適した和声が2つ以上あるということなので、
その中からランダムで optinumFuncNum を決定するという方法もある。
*/
if(remainder < minDiff ) {
minDiff = remainder;
optinumFuncNum = i ;
}
} // for
return optinumFuncNum;
}
public void setCadenceValue(){
int[] standardChord = new int[4];
for(int i =0; i < Scale.presentScale.length; i++) {
standardChord = Harmony.getChord(i+1); // +1は機能番号にするため。
for(int j = 0; j < Scale.presentScale.length; j++ ){
cadenceValueTable[i][j] = getChordProgressionValue(standardChord, Harmony.getChord(j+1) );
/*
・ i == j のとき必ず0が入る
・ cadenceValueTableの [i][j] と [j][i] は+- が反転した値である
以上のことを踏まえて、Code を簡略化できる。
※ただしBalancerのシステム変更の際、不適切になる可能性がある。
*/
}
}
}
public int getChordProgressionValue( int[] chord1, int[] chord2 ){
int interval;
int value;
for( int i =0; i < chord1.length ; i++){
for(int j = 0; j< chord2.length; j++){
interval = chord2[j] - chord1[i];
if(diff < 0 ){
diff += 12 ; //マイナス値をプラスの音程数に直す。
}
value += intervalValueD_SD[interval];
}
}
return value;
}
} // class HarmonyBalancer
class Rhythm { // OK
int[] presentBeat;
int[][] 4beat = { 4, 4, 4, 4 }, { 6,4,6,4 };
Meter meter;
Dynamics dynamics;
public Rhythm() {
presentBeat = 4beat;
meter = new Meter(120);
dynamics = new Dynamics();
}
public void playRhythm(){
int t;
int v;
for(int i=0; i< presentBeat.length; i++){
t = meter.num2Time(presentBeat[0][i]);
v = dynamics.num2Volume(presentBeat[1][i]);
Sound s = new Sound( t, v );
}
}
} // class Rhythm
class Dynamics { // OK
int[] presentLevels;
int[] nineLevels = { 0, 100,200,300,400, 500, 600,700,800,900 }
public Dynamics (){
presentLevels = nineLevels;
}
public int num2Volume(int num){
num = presentLevels[num];
return num;
}
} // class Dynamics
public class Meter { // OK
int bpm;
int oneBeat;
int oneBar;
public Meter (int bpm){
this.bpm = bpm;
oneBeat = 1000 / ( bpm / 60 ) ; // 1000 (= 1秒)
oneBar = oneBeat * 4;
}
public int num2Time ( int num ) {
num = oneBar / num ;
return num;
}
} // class Meter
public class Sound implements Runnable { //OK
static final int bit = 16;
static final int ch = 1;
static int frame = 2;
static final int SR = 44100; //SampleRate
static final AudioFormat af = new AudioFormat(SR, bit, ch, true, true);
static final DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
static SourceDataLine line;
static final int BUFFER = 10000;
float fadeTime = 30; // fadeIn/Out は 10msec でも可能なはず。
int fadeSR = Math.round(SR * fadeTime/1000);
float freq;
float vol;
int time;
int[] soundArray;
byte[] playableArray;
public Sound (float freq, int time, float vol ) {
this.freq = freq;
this.vol =(float)( vol * (Math.pow(2, bit - 1) / 1000 )); // 最大値の1000分割単位
this.time = time * ( SR / 1000 ); // 1000分の1秒(mSec)単位
this.soundArray = new int[this.time];
this.playableArray = new byte[ ch * frame * this.time];
this.soundArray = writeWave();
this.soundArray = fadeProcess(this.soundArray);
this.playableArray = getPlayableArray(this.soundArray);
}
public void run() {
int restLength = playableArray.length;
int offset = 0;
try {
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); // AudioをInitialize
line.open(af);
line.start();
if (!RixUI.stopped) {
while (BUFFER < restLength && !RixUI.stopped) {
line.write(playableArray, offset, BUFFER);
restLength -= BUFFER;
offset += BUFFER;
}
line.write(playArray, offset, restLength);
}
line.drain();
//System.out.println("AudioFormat: " + af.toString());
} catch (LineUnavailableException ex) {
Logger.getLogger(Oscillator.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int[] writeWave(){
return s;
}
public int[] fadeProcess(int[] s) {
float turnDown;
for (int i = 0; i < fadeSR; i++) {
turnDown = (float)Math.pow((i / (float)fadeSR),2);
s[i] =Math.round( s[i] * turnDown);
s[s.length -1 - i] =Math.round(s[s.length -1 - i] * turnDown );
//System.out.println("turnDown= "+ turnDown);
}
return s;
}
public byte[] getPlayableArray(int[] s){
int nBAdd;
for (int i = 0; i < soundArray.length; i++) {
nBAdd = i * frame * ch;
playableArray[nBAdd + 0] = (byte) ((soundArray[i] >>> 8) & 0xFF);
playableArray[nBAdd + 1] = (byte) (soundArray[i] & 0xFF);
}
return playableArray;
}
} // class Sound
public class Sine extends Sound { // OK
public Sine (){
super();
}
public int[] writeWave(int[] s, float f, float v){
int waveOneSR = Math.round(SR / f); // harmE 0x03 で f=55000 SRを超過
int[] waveOne = new int[waveOneSR];
float waveXPos;
float waveY;
for (int i = 0; i < waveOneSR; i++) {
waveXPos = (float) i / (float) waveOneSR;
waveY = (float) Math.sin(waveXPos * 2.0 * Math.PI);
waveOne[i] = Math.round(waveY * v);
//System.out.println("TEST-1 "+ waveOne[i]);
}
int startPos = 0;
int setPos = 0;
int waveLap = soundArray.length;
int nWave;
while (waveLap > 0) {
nWave = Math.min((waveOne.length - startPos), waveLap);
try {
System.arraycopy(waveOne, startPos, s, setPos, nWave);
} catch (Exception e) {
System.out.println("myERROR:Oscillator2.writeWave | System.arraycopy("+waveOne.length +
", "+startPos+", "+s.length+", "+setPos+", "+ nWave+");" );
}
waveLap -= nWave;
setPos += nWave;
startPos = (startPos + nWave) % waveOne.length;
// soundForm=0x030303 により waveOne.length = 0 の Error
}
return s;
}
} // class Sine
class PercussiveNoise extends Sound{ // BAK 2014.11.08
int vibration;
public PercussiveNoise (float f, int t, float v, int vibration ){
super(f,t,v);
this.vibration = vibration * ( SR / 1000 ); // 1000分の1秒単位
this.soundArray = writeWave(soundArray, freq, vol, vibration);
this.soundArray = fadeProcess(this.soundArray);
this.playableArray = getPlayableArray(this.soundArray);
}
public int[] writeWave(int[] s, float f, float v, int vibration){
float v2;
for ( int i =0; i < vibration ; i++ ){
v2 = v - i * ( v / vibration );
s[i] = (int) Math.floor(Math.random() * v2);
}
int rest = s.length - vibration ;
for ( int i =0; i< rest; i++ ){
s[vibration + i] = 0;
}
return s;
}
} // class PercussiveNoise
// EOF
登録:
投稿 (Atom)