微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在处理中 - 整个动画中只有一个 soundFile,但只有一个类对象与声音交互

如何解决在处理中 - 整个动画中只有一个 soundFile,但只有一个类对象与声音交互

我对 Processing 还是很陌生,我正在尽我最大的努力弄清楚这个项目:(

我正在尝试创建一个有序列的动画,在整个动画中播放一个 soundFile。但是,只有 class Two 需要有声音响应元素。

所有三个类对象在各自的草图文件中都可以正常工作。但当他们在一个草图中作为班级时则不然。

现在我只有第二类的声音文件,因为我不知道如何拥有相同的声音文件但响应不同的类。

当不同的类需要打开和关闭时,我不确定 背景 是如何工作的。 我也不确定我的排序方式是否正确...... 我很感激任何帮助。谢谢各位!

One objectone;
Two objecttwo;
Three objectthree;

int myAnimationCounter = 0; //set myAnimationCounter incerment to 0,so allows to reset to 0 to start the animation.
int myAnimationCounter1 = 0;
int myAnimationCounter2 = 0;//set a parallel myAnimationCounter incerment to 0.
boolean startAnimation = false;  //Boolean switch to control starting animation.
boolean openingAnimation = false;

void setup() {
  size(displayWidth,displayHeight); //sketch present
  frameRate(50);
  objectone=new One();
  objecttwo=new Two();
  objectthree=new Three();
}

void draw() {
  
  if (openingAnimation) { //start the opening seq when press spacebar
    if ( myAnimationCounter>0 && myAnimationCounter<750) {
      objectone.show1();
    }
    myAnimationCounter++;
  }
  
  //when clicking the mouse 'openingAnimation' stops,playing 'startAnimation'
  
  if (startAnimation) {        
    if (myAnimationCounter1 > 0  && myAnimationCounter1 < 2500) {
        objecttwo.update2();
        objecttwo.show2();
      } else
      
        if (myAnimationCounter1 > 2500  && myAnimationCounter1 < 3000) {
objectthree.update3();                  
objectthree.show3();
        }
    myAnimationCounter1++;

//rect shape drawing at the bottom of the screen showing the playing progression of the animation

    if (myAnimationCounter2 > 0 && myAnimationCounter2 < 9000) { //independent animation through out the whole animation 
      fill(d);
      nostroke();
      rect(width,height-10,10,width/myAnimationCounter2);
    }
    myAnimationCounter2++;
  }
}//end of draw


void keypressed() {
  if (key == ' ') {
    openingAnimation = true;
  }
}

void mousepressed() {
  if (mousepressed) {
    startAnimation = true;
    openingAnimation=false;

    myAnimationCounter=0;
    myAnimationCounter1=0;
    myAnimationCounter2=0;
  }
class One {
  void show1() {
 background(bg);
}
}
class Two {
  import processing.sound.*;
  SoundFile loadSound; 
  Amplitude measureVol;
 void update2() {
    loadSound = new SoundFile(this,"music.mp3"); 
    loadSound.loop();  
    measureVol = new Amplitude(this);
    measureVol.input(loadSound);
  } 
  void show2() {
   float howLoud = measureVol.analyze();
}
}
class Three {
 void update3() {
  background(0);
}
 void show3() {
}
}

解决方法

您可以将声音代码放在自己单独的类中。然后,在 Setup 中实例化该类并作为参数注入到类 Two 中。确保用于提供音频功能的此类具有用于您希望从 Two 中调用的操作的公共方法。

例如:

class MyAudioClass {

SoundFile loadSound; 
Amplitude measureVol;

    public MyAudioClass() {
        measureVol = new Amplitude(this);
    }

    public void loadSound(String soundFileName) {
        loadSound = new SoundFile(this,soundFileName);
        measureVol = input(loadSound);
    }

    public void playSound() {
        loadSound.loop();
    }

    public float getHowLoud() {
        return measureVol.analyze();
    }
}

然后,在 Two 中:

class Two {
    private MySoundClass mySoundClass;
  
    // using Constructor Dependency Injection
    public Two(MySoundClass mySoundClass) {
        this.mySoundClass = mySoundClass;        
    }

    public float showHowLoud() {
        return mySoundClass.getHowLoud();
    }

(注意:我没有使用过Processing,我只是根据最佳猜测转换你写的东西——所以可能需要一些调整。)

IDK 如果您还需要将类注入到 OneThree。也许您只需要在 Setup 中开始播放?只要您在 Setup 中处理与 Two 中相同的实例(或您注入的任何其他类),事情应该没问题。

这种编码模式通常被称为依赖注入或作为控制反转的一个例子,并且非常有用。一种变体是使用 setter 方法而不是构造函数来传递您的声音资源类。

控制反转——DI背后的概念

这表明类不应静态配置其依赖项 但应该由外部的其他类配置。

这是S.O.L.I.D的第五项原则——五项基本原则 鲍勃叔叔的面向对象编程和设计——其中指出 一个类应该依赖于抽象而不是具体化(在 简单的术语,硬编码)。

按照原则,一个班级应该专注于完成 它的职责,而不是创建它需要的对象 履行这些职责。这就是依赖注入的地方 发挥作用:它为类提供所需的对象。

以上摘自文章A Quick Intro to Dependency Injection

,

根据您的代码,这是我理解的顺序:

  • 如果按下空格并且 One 的实例将显示前 750 个“滴答声”(15 秒,每秒 50 帧)
  • 如果按下鼠标,所有计数器和标志都会重置
  • Two 的一个实例更新并显示第一个 2500 个“滴答声”(50 秒 50 帧)
  • 然后 Three 的实例将更新 并显示 2500 到 3000 个“滴答声”(50 秒到 60 秒,每秒 50 秒)
  • 同时,对于前 9000 个“滴答声”(180 秒,每秒 50 帧),将显示一个缩小的矩形

关于background():它只是清除先前绘制的内容,否则绘制的内容会累积。

以这个基本示例为例:

void setup(){
  size(300,300);
  background(255);
}

void draw(){
  if(mousePressed){
    line(mouseX,mouseY,pmouseX,pmouseY);
  }
}

void keyPressed(){
  background(255);
}

当您在屏幕上拖动鼠标时,线条不断被绘制(甚至在彼此之上)。当按下一个键时,背景(设置为白色)会重新绘制在所有先前行的顶部,并清除它们。

这给您的代码带来了另一个小问题:

void mousePressed() {
  if (mousePressed) {
    startAnimation = true;
    openingAnimation=false;

    myAnimationCounter=0;
    myAnimationCounter1=0;
    myAnimationCounter2=0;
  }
}

mousePressed() 函数仅在鼠标按下时被调用,这使得检查鼠标是否按下的 if 条件变得多余。这应该足够了:

void mousePressed() {
  startAnimation = true;
  openingAnimation=false;

  myAnimationCounter=0;
  myAnimationCounter1=0;
  myAnimationCounter2=0;
}

关于背景声音,它似乎在 update2() 中每秒加载多次:

class Two {
  import processing.sound.*;
  SoundFile loadSound; 
  Amplitude measureVol;
 void update2() {
    loadSound = new SoundFile(this,"music.mp3"); 
    loadSound.loop();  
    measureVol = new Amplitude(this);
    measureVol.input(loadSound);
  } 
  void show2() {
   float howLoud = measureVol.analyze();
}
}

我的假设是 update() 将被多次调用以更新数字,而 show() 将被多次调用以呈现这些值(如文本、形状等)

由于您在 Two 中实例化了 setup(),因此您可以在 Two 的构造函数中加载一次声音:

class Two {

  SoundFile loadSound; 
  Amplitude measureVol;

  float howLoud;
  // this gets called once when you make a new instance (e.g = new Two())
  Two() {
    loadSound = new SoundFile(this,"music.mp3"); 
    loadSound.loop();  
    measureVol = new Amplitude(this);
    measureVol.input(loadSound);
  }

  void update() {
    howLoud = measureVol.analyze();
  } 
  void show() {
    fill(127);
    text("Two instance show() -> howLoud: " + howLoud,10,15);
  }
}

通过这种方式,声音被创建并循环一次,然后仅在调用 update() 时进行分析(在 startAnimation 的前 2500 次更新内)

为了保持一致,我建议使用 update()/show() 并理想地将实例命名为类似于其他变量(例如 objectOneobjectTwoobjectThree )。理想情况下,import 语句应位于代码的顶部。

以下是对您的代码稍加调整的版本,并考虑到了上述说明:

import processing.sound.*;

One objectOne;
Two objectTwo;
Three objectThree;

int myAnimationCounter = 0; //set myAnimationCounter incerment to 0,so allows to reset to 0 to start the animation.
int myAnimationCounter1 = 0;
int myAnimationCounter2 = 0;//set a parallel myAnimationCounter incerment to 0.
boolean startAnimation = false;  //Boolean switch to control starting animation.
boolean openingAnimation = false;

color bg = color(255);
color d = color(192,0);

void setup() {
  size(displayWidth,displayHeight); //sketch present
  frameRate(50);

  objectOne   = new One();
  objectTwo   = new Two();
  objectThree = new Three();
}

void draw() {
  background(255);

  if (openingAnimation) { //start the opening seq when press spacebar
    if ( myAnimationCounter>0 && myAnimationCounter<750) {
      objectOne.show();
    }
    myAnimationCounter++;
  }

  //when clicking the mouse 'openingAnimation' stops,playing 'startAnimation'

  if (startAnimation) {        
    if (myAnimationCounter1 > 0  && myAnimationCounter1 < 2500) {
      objectTwo.update();
      objectTwo.show();
    } else if (myAnimationCounter1 > 2500  && myAnimationCounter1 < 3000) {
      objectThree.update();                  
      objectThree.show();
    }
    myAnimationCounter1++;

    //rect shape drawing at the bottom of the screen showing the playing progression of the animation

    if (myAnimationCounter2 > 0 && myAnimationCounter2 < 9000) { //independent animation through out the whole animation
      fill(d);
      noStroke();
      rect(mouseX,width / myAnimationCounter2);
    }
    myAnimationCounter2++;
  }

  // debug
  fill(127);
  text("openingAnimation: " + openingAnimation + "\n" + 
    "startAnimation: " + startAnimation + "\n" + 
    "myAnimationCounter: " + myAnimationCounter + "\n" +
    "myAnimationCounter1: " + myAnimationCounter1 + "\n" + 
    "myAnimationCounter2: " + myAnimationCounter2 + "\n",30);
}//end of draw


void keyPressed() {
  if (key == ' ') {
    openingAnimation = true;
  }
}

void mousePressed() {
  startAnimation = true;
  openingAnimation=false;

  myAnimationCounter=0;
  myAnimationCounter1=0;
  myAnimationCounter2=0;
}

class One {
  void show() {
    background(bg);
    text("One instance show()",15);
  }
}

class Two {

  SoundFile loadSound; 
  Amplitude measureVol;

  float howLoud;

  Two() {
    loadSound = new SoundFile(this,15);
  }
}

class Three {

  void update() {
  }
  void show() {
    background(0);
    text("Three instance show()",15);
  }
}

此外,我还做了一些其他的小改动:

  • 我在 text() 的底部添加了 draw(),以便更轻松地调试行为。您可以可视化布尔值和计数器的值。
  • 每个 show() 方法还使用 text() 来可视化正在渲染的实例
  • 目前还不清楚 rect() 调用的目的是什么,但坐标在屏幕外。作为测试,我已将 rect() 位置对齐到鼠标位置:随意将其更改为对您的应用程序有意义的内容。如果是动画持续时间的可视化,则假设总持续时间为 9000 个计数。仍然不清楚意图是将其呈现为水平条还是垂直条(可能是垂直的?)以及它是否应该增长或缩小(目前它会缩小)

我还注意到 myAnimationCounter2myAnimationCounter1 的更新时间/速率相同,这使它们完全相同。如果是这种情况,也可以使用 myAnimationCounter1 来绘制矩形,并且可以丢弃 myAnimationCounter2 以简化代码。如果您确实计划在将来独立于 myAnimationCounter1 更新 myAnimationCounter2,那么值得保留它。

每次用户点击计数器都会重置,但是打开动画只会在用户按下空格键后显示一次,但无法重置。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。