【问题标题】:How to solve infinite loop for generated music?如何解决生成音乐的无限循环?
【发布时间】:2017-02-06 15:45:51
【问题描述】:

我有一个程序,我想创建一个随机生成的音乐小节(每小节 4 拍,使用 C 大调音阶)。但是,我无法理解数学并不断溢出我的 do while 循环,为我想避免的小节创建超过 4 个注释。

我正在使用由我的导师创建的 aServe,但基本上是向播放我评论过的参数的振荡器打开一个流。

/* Program for randomly written bar of 4/4 in C Major */

#include "aservelibs/aservelib.h"
#include <stdio.h>
#include <stdlib.h>

//macros
#define SEMIBREVE       (1.0)
#define MINIM           (1.0/2)
#define CROTCHET        (1.0/4)
#define QUAVER          (1.0/8)
#define SEMIQUAVER      (1.0/16)
#define DEMISEMIQUAVER  (1.0/32)

#define C   (261.63)
#define D   (293.66)
#define E   (329.63)
#define F   (349.23)
#define G   (391.99)
#define A   (440.00)
#define B   (493.88)

int millisec(int bpm, double note) {
    return (int)(
                 60      /* seconds */
                 * 1000  /* milliseconds per second */
                 * 4     /* crotchets per semibreve */
                 * note
                 / bpm
                 );
}

int main()
{
    int bpm = 120; //BPM Value
    double Length[] = {SEMIBREVE, MINIM, CROTCHET, QUAVER, SEMIQUAVER, DEMISEMIQUAVER}; //Array of Note Lengths
    double Pitch[] = {C, D, E,F, G, A, B}; //Array of CMajor Scale Freq

    int randLength = (rand() % 6); //random positions for note length
    int randPitch = ( rand() % 7); //random positions for note pitch
    double barTotal = 0; //amount of bar currently completed

    do {
        if(barTotal < 1) //if bar total is smaller than 1
        {
            barTotal = Length[randLength] + barTotal; //add note to total

            aserveOscillator(0, Pitch[randPitch], 1, 2); //Starts stream to oscialltor
                //aserveOscillator(Index,Frequency,Amplitude,WaveType);
            aserveSleep(millisec(bpm, Length[randLength])); //play the notes for the length of time specified in milliseconds

            randLength = (rand() % 6); //prepare next random note
            randPitch = (rand() % 7); //prepare next random pitch

            //Output
            printf("Note: ");
            printf("%lf", Pitch[randPitch]);
            printf("\n For: ");
            printf("%lf", Length[millisec(bpm,randLength)]);
            printf("\n With Bar Total: ");
            printf("%lf", barTotal);
            printf("\n\n");
        }
        else
        {
            if(barTotal != 1) //if bar total is bigger than 4
            {
                randLength = (rand() % 6); //try another number
            }
        }

    } while (barTotal != 1); //will stop once reaches 4

    return 0;
}

【问题讨论】:

  • 在您的代码中有几个与值 4 的比较,但似乎整个音符 (SEMIBREVE) 的值为 1.0。如果 1.0 表示条的长度,那么这些比较似乎是不正确的。
  • barTotal 是一个double,您正在向其中添加分数。我认为它完全等于 4(从而脱离循环)的可能性非常小。此外,您将它与 4 而不是 4.0 进行比较,我不确定这意味着什么。为什么不使用 int 来记录笔记的数量?
  • @dazedandconfused 我已经修改了我认为可以改变这一点的代码。
  • @yano 如果我错了,请纠正我,但我想要由随机音符长度组成的随机音符数量来填充 4/4 条 - 而不仅仅是 x 个音符。
  • 您需要随时间播种随机函数,以便在每次运行时获得不同的值:stackoverflow.com/questions/8314370/…

标签: c audio while-loop infinite-loop


【解决方案1】:

考虑以不同的方式思考问题。将条视为“n”个插槽,其中 n 是您拥有的最细粒度的音符类型。因此,在您的情况下,条形图是一组 32 个插槽。不要将您的数字表示为分数,而是使用整数类型来显示每个“插槽”中有多少。因此,DEMISEMIQUAVER 占用 1 个插槽,它可以表示为 int 而不是 (1.0 / 32.0),这会引入一些潜在的丑陋问题。

一旦你这样做了,解决方案就更简单了:

1) 当前栏还剩多少个槽位? 2) 从小于剩余槽位的音符池中随机选择一个音符 3) 重新计算添加新笔记后还剩多少空间 4) 如果剩余空间为零,则继续下一个小节。

以下是您的代码,适用于这种新方法。尚未经过全面测试,但它应该避免迄今为止讨论的大部分(如果不是全部)陷阱。

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//macros
#define SEMIBREVE       (32)
#define MINIM           (16)
#define CROTCHET        (8)
#define QUAVER          (4)
#define SEMIQUAVER      (2)
#define DEMISEMIQUAVER  (1)

#define C   (261.63)
#define D   (293.66)
#define E   (329.63)
#define F   (349.23)
#define G   (391.99)
#define A   (440.00)
#define B   (493.88)

int GetMaxIndex(int remainingLength)
{
    // Returns the largest upper bound of the Length array that
    // should be considered based on how much room remains in 
    // the current bar.
    int result;
    if(remainingLength == 32) result = 5;
    if(remainingLength < 32) result = 4;
    if(remainingLength < 16) result = 3;
    if(remainingLength < 8) result = 2;
    if(remainingLength < 4) result = 1;
    if(remainingLength < 2) result = 0;
    return result;

}

int main()
{
    double Pitch[] = {C, D, E,F, G, A, B}; //Array of CMajor Scale Freq

    int bpm = 120; //BPM Value
    int Length[] = {DEMISEMIQUAVER, SEMIQUAVER, QUAVER, CROTCHET, MINIM, SEMIBREVE}; //Array of Note Lengths
    char* Labels[] = {"DEMISEMIQUAVER (Thirty Second)", "SEMIQUAVER (Sixteenth)", "QUAVER (Eighth)", "CROTCHET (Quarter)", "MINIM (Half)", "SEMIBREVE (Whole)"}; 
    int remainingThisBar;
    int barsToGenerate = 4;

    int randLength = (rand() % 6); //random positions for note length
    int randPitch; //random positions for note pitch
    int maxIndex;
    int randIndex;

    srand(time(NULL));

    for(int barNumber = 0; barNumber < barsToGenerate; barNumber++)
    {
        printf("Beginning bar: %i\n", barNumber);
        remainingThisBar = 32;

        while(remainingThisBar > 0)
        {
            maxIndex = GetMaxIndex(remainingThisBar);  // What is the biggest note index we still have room for?
            randIndex = maxIndex == 0 ? 0 : (rand() % maxIndex); // Get a random note between 0 and maxIndex

            randPitch = ( rand() % 7);      // Random positions for note pitch
            randLength = Length[randIndex]; // Length in 32nds
            remainingThisBar -= randLength; 

            // Output
            printf("\tNote: %s @ %f\n", Labels[randIndex], Pitch[randPitch]);
            printf("\t32nds remaining in bar: %i\n", remainingThisBar);
            printf("\n");

            /* TODO - Output note via aServe*/
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-23
    • 1970-01-01
    • 2020-05-18
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-01
    相关资源
    最近更新 更多