有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ringbuffer没有读取正确的数据

我开始做一个项目,以产生不同频率的声音。在这个目标中,我使用了3个对象:

  • 一个发生器,用于产生正弦信号并生成编号的声音包(带有一个简单的整数ID),以44100 Hz的频率采样,并使用“可观察”模式
  • “环形缓冲器”是发电机的“观察者”。它将数据包存储在用作缓冲区的数组(而不是列表)中
  • 读取器,用于将声音数据读入环形缓冲区

Main类中,我在创建缓冲区和创建读取器之间创建了一个中断(Thread.sleep)。它允许我在讲座开始前填充一点环形缓冲区(我也想看看会发生什么…)

问题在于环形缓冲区(代码如下)。如果课间休息时间足够短,以至于讲座开始时没有填满铃声缓冲区,那么一切似乎都差不多正常。 但是,如果我的缓冲区被填满(在许多其他无法解释的情况下),我的声音就会有很多寄生虫。如果我分析读取数据包ID的结果,我会得到:

Buffer.load - packet ID : 63 - buffer pos. = 62
Buffer.load - packet ID : 64 - buffer pos. = 63
Buffer.load - packet ID : 65 - buffer pos. = 64
Buffer.read - packet ID : 65 - buffer pos. = 2
Buffer.read - packet ID : 65 - buffer pos. = 3
Buffer.read - packet ID : 65 - buffer pos. = 4
Buffer.read - packet ID : 65 - buffer pos. = 5

read方法总是发送相同的数据包ID,无论读卡器在缓冲区中的位置如何。但是,加载方法似乎工作正常,并在以下位置加载以下ID

public class Buffer2 implements Observer {

    private Object[] buffer;
    /*
     * important note about the buffer : 
     * It is an array and not a list.
     * So, it will be impossible to shift on the left or on the right the elements
     * (a method like deleteFirst or similar doesn't exsits for arrays)
     * in case of lecture (then suppression) or adding of en element.
     * So, I'll use three variables : one to know the lecture position in the buffer
     * one for the writing position
     * a last one to know the volume data into the buffer.
     */
    private int inBuffer, bufferSize, first, last;

    public Buffer2 (int bufferSize) {
        buffer = new Object[bufferSize];
        inBuffer=0;
        last=0;
        this.bufferSize=bufferSize;
    }

    public synchronized byte[] read () {
        while (inBuffer==0) {
            try {
                wait();
                System.out.println("Buffer.read = null");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // See the method "load()" for the explanation of the next line
        first=(first+1)%bufferSize;
        inBuffer--;
        /*
         * This method awake the threads which were sleeping because of the load() method
         * when the buffer is full 
         */
        notifyAll();
        Object[] temp = (Object[]) buffer[first];
        System.out.println("Buffer.read - packet ID : "+(int)temp[0]+" - buffer pos. = "+first);
        return (byte[]) temp[1];
    }

    public synchronized void load (Object[] data) {
        while (inBuffer==bufferSize) {
            try {
                System.out.println("Buffer.load : full !");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        /*
         * Method to calculate the position to add the new value : 
         * Ex : buffer size = 10 and we just read the 3rd position
         * (3+1)%10 = 4 => the new value will be added in the 4th position of the array
         * Ex2 : if the position was 9 :
         * (9+1)%10=0 => the value would be added at the position 0 of the array.
         */
        last = (last+1)%bufferSize;
        inBuffer++;
        System.out.println("Buffer.load - packet ID : "+(int)data[0]+" - buffer pos. = "+last);
        buffer[last]=data;
        /*
         * Awake for all waiting threads locked
         * because the buffer was empty
         */
        notifyAll();
    }

    @Override
    public void update(Observable observable, Object obj) {
        if (observable instanceof Generator) {
            load((Object[]) obj);           
        }       
    }
}

怎么了?谢谢你的回答

经过几次测试和检查,我注意到了几件事:

  • update()方法接收不同的值,并用这些值调用load()方法。所以,它似乎按照要求工作
  • 在用指令buffer[last]=data;更改缓冲区之前,我检查了数据是否来自update方法:是的,它们是。所以,它起作用了
  • 在修改了缓冲区之后,我检查了整个缓冲区中的数据(对于测试,我只使用了一个有10个值的缓冲区)。问题是:所有的值都是相同的,即使它们是在数组的前面引入的。换句话说,当我在数组中加载一个新值时,所有值都会被修改,并与最后一个值相等

多亏了托马斯的建议,让我能更准确地找出问题所在,但我还是解决不了

谁能帮我更多

谢谢大家


共 (1) 个答案

  1. # 1 楼答案

    我终于找到并解决了这个问题,借助托马斯的建议。事实上,当我通过update()方法接收数据时,我产生了副作用。 接收到的数据包是一个Object[2],其中的两个对象是另一个Object[]用于报头,另一个byte[]用于数据本身

    因此,我必须读取这个数据包的每个数组的每个值,才能将它们写入一个“单一使用”对象(Object[] packet = new Object[2]

    因此update()方法的代码是:

        @Override
        public synchronized void update(Observable observable, Object obj) {
            if (observable instanceof Generator) {
                // A packet contain a header (header) and datas (data)
                Object[] packet = new Object[2];
    
                    /*
                 * The header contain 3 datas : 
                 * [0] ID
                 * [1] The number of byes in the array of bytes
                 * [2] the AudioFormat
                 */
                Object[] header = new Object[3];
                header[0]= ((Object[]) ((Object[]) obj)[0])[0];
                header[1]= ((Object[]) ((Object[]) obj)[0])[1];
                header[2]= ((Object[]) ((Object[]) obj)[0])[2];
                // I reconstruct the hehader in the position [0] in the packet
                packet[0]=header;
    
    
                byte[] data = new byte[(int) header[1]*4];
                for (int i=0; i< data.length ; i++) {
                    /*
                     * Reading each byte in the [i] position of the bytes[]
                     * This array of bytes is in the position [1] of the array which is the Object[] obj
                     */
                    data[i] =  ((byte[]) ((Object[]) obj)[1])[i];
                }
                // I reconstruct the data in the position [1] of the packet
                packet[1]=data;
                // I feed the load() method with the packet
                load(packet);
            }       
        }
    

    我希望我的回答能帮助别人。祝你今天愉快