14 Replies Latest reply: Nov 2, 2010 12:57 PM by 804900 RSS

    FFT noise reduction problem

    804900
      hello, me again.

      I've been looking into java examples of FFT, mainly from this post http://forums.sun.com/thread.jspa?threadID=5426904&start=0&tstart=0 and am having trouble gettin rid of the output noise (much like the author). I took the advice of the other poster in the topic and have replaced the byte [] -> short [] -> double[] with the straight byte[] -> double[] from this post http://forums.sun.com/thread.jspa?threadID=5420508&tstart=30 but that seems to return a file of noise.

      i am unsure where the error occurs in the byte[]->short[] method:
      public ByteAndShort2(byte[] array, boolean bigEndian) {
                short[] unsignedByteArray;
                int[] unsignedShortArray;
                int N = array.length;
                isBigEndian = bigEndian;
                
      
                if (N%2 != 0) {
                     shortArray = new short[(N+1)/2];
                     byteArray = new byte[N+1];
                     unsignedByteArray = new short[N+1];
                     unsignedShortArray = new int[(N+1)/2];
                     
                     for (int i = 0; i < N; i++) {
                          unsignedByteArray[i] = (short) (array[i] + 128);
                          byteArray[i] = array;
                     }
                     unsignedByteArray[N] = 1;
                     byteArray[N] = 0;
                }
                else {
                     shortArray = new short[N/2];
                     byteArray = new byte[N];
                     unsignedByteArray = new short[N];
                     unsignedShortArray = new int[(N)/2];
                     
                     for (int i = 0; i < N; i++) {
                          unsignedByteArray[i] = (short) (array[i] + 128);
                          byteArray[i] = array[i];
                     }               
                }
                
                if (isBigEndian) {
                     for (int i = 0; i < unsignedShortArray.length; i++) {
                          unsignedShortArray[i] = (int) (256 * (unsignedByteArray[i*2]) + (unsignedByteArray[i*2+1]));
                     }               
                }
                else {
                     for (int i = 0; i < shortArray.length; i++) {
                          unsignedShortArray[i] = (int) (256 * (unsignedByteArray[i*2+1]) + (unsignedByteArray[i*2]));
                     }
                }
                
                for (int i = 0; i < shortArray.length; i++) {
                     shortArray[i] = (short) (unsignedShortArray[i] - 128 * 257);
                }
           }


      any insight/links/etc would be fantastic

      many thanks,
      Fiona
        • 1. Re: FFT noise reduction problem
          captfoss
          I'm pretty sure the code to do that would be:
          public short[] ByteAndShort2(byte[] array, boolean bigEndian) {
          
            short output[] = new short[array.length / 2];
          
            // Convert our output
            for (int i = 0; i < array.length-1, i += 2) {
              output[i/2] = bigEndian ?
                    ((array[i] << 8)    && (0xff00)) || (array[i+1] && 0x00ff) :
                    ((array[i+1] << 8)) && (0xff00)) || (array[i]   && 0x00ff);
            }
          
            return output;
          }
          Note the for loop going to array.length-1 should handle both the even and odd cases... If you had 8 elements, for instance, you'd go (<7)0246 and if you had 9 elements, you'd go (<8)0246... so you'd have the correct procedure both ways.

          And the bit shifting and masking should produce "clean" output...
          • 2. Re: FFT noise reduction problem
            804900
            thanks for the reply,

            Im sure the code works, but the netbeans IDE I am using is throwing some syntax errors.

            it says that
            - operator && cannot be applied to int,int
            - operator && cannot be applied to byte,int
            - ; expected
            - not a statement
            - inconvertable types, required short, found boolean

            I assume that it has been written in if statement shorthand, so that may be where I am getting confused

            thanks again,
            Fiona

            Edited by: Fillis52 on 26-Oct-2010 11:30
            • 3. Re: FFT noise reduction problem
              captfoss
              Fillis52 wrote:
              Im sure the code works, but the netbeans IDE I am using is throwing some syntax errors.
              I didn't actually compile or test the code before posting it... so it's assumed you'd fix my stupid errors yourself ;-)
              - operator && cannot be applied to int,int
              - operator && cannot be applied to byte,int
              && should have been just &, I put a logical and where I meant bitwise and...
              || should have been just |, I put logical or where I meant bitwise or...
              - ; expected
              Just a typo in my for loop
              - not a statement
              - inconvertable types, required short, found boolean
              Probably a result of the previous errors... might need to be cast to a short, perhaps.

              Try this and fix whatever debug errors there are in it. I assume you're not a CS1000-level student so fix the obvious stuff.
              public short[] ByteAndShort2(byte[] array, boolean bigEndian) {
               
                short output[] = new short[array.length / 2];
               
                // Convert our output
                for (int i = 0; i < array.length-1; i += 2) {
                  output[i/2] = bigEndian ?
                        (short)(((array[i] << 8)    & (0xff00)) | (array[i+1] & 0x00ff)) :
                        (short)(((array[i+1] << 8)) & (0xff00)) | (array[i]   & 0x00ff));
                }
               
                return output;
              }
              • 4. Re: FFT noise reduction problem
                804900
                i had noticed the error in the for loop, and had fixed that. had also played around with the code to reduce the errors

                now have
                output[i/2] =(short) (bigEndian ? ((array[i] << 8) & (0xff00)) | (array[i + 1] & 0x00ff) : ((array[i+1] << 8)) & (0xff00))) | (array[i] & 0x00ff);
                this seems to have solved the problems mentioned earlier.

                system now seems to have less noise than with the previous code, but is still not perfect.

                will leave for now, as it is only being used as a research tool and doesnt need to be perfect.


                thanks again, i was a little over my head as previously the most complicated programming i had done in java was basic networking!
                • 5. Re: FFT noise reduction problem
                  captfoss
                  Fillis52 wrote:
                  this seems to have solved the problems mentioned earlier.

                  system now seems to have less noise than with the previous code, but is still not perfect.
                  Well, if you're converting from byte to short, short to double... you may have some unclean operations in your short-to-double conversions.

                  Alternately, the noise could be the result of improperly handling the signedness of the byte samples...
                  • 6. Re: FFT noise reduction problem
                    804900
                    This is now not so much a noise problem, but I have decided to move onto the next part of my application: saving the sound as a wav

                    The sound is saved, but for some reason only the last half or so of the sound is actually in the file (which is backed up by the length of the file, i.e is shorter than it should be)

                    here is what i have, and i assume the problem lies in the size of the byte[], but i cant see which array is the problem
                                File soundFile = file2;
                                audioInputStream = AudioSystem.getAudioInputStream(soundFile);
                                AudioFormat audioFormat = audioInputStream.getFormat();//used to get old format of sound
                    
                                out = new FileOutputStream(tempOutputFile);
                                audioFormatOld = audioInputStream.getFormat();
                                audioFormatNew = new AudioFormat((int) (audioFormatOld.getSampleRate() * sampleChange), audioFormatOld.getSampleSizeInBits(), 1, true, false);
                    
                                FileInputStream fis = new FileInputStream(file2);
                                System.out.println(fis.available());
                                AudioInputStream ais = new AudioInputStream(fis, audioFormatNew, (int) fis.available() / audioFormatNew.getFrameSize());
                                byte[] rawData = new byte[ais.available()];
                                ais.read(rawData);
                    
                                DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
                    
                                Mixer.Info[] mixerInfo =
                                        AudioSystem.getMixerInfo();
                                System.out.println("Available mixers:");
                                for (int cnt = 0; cnt < mixerInfo.length;
                                        cnt++) {
                                    System.out.println(mixerInfo[cnt].getName());
                                }
                    
                                Mixer mixer = AudioSystem.getMixer(mixerInfo[6]);
                    
                                soundLine = (SourceDataLine) mixer.getLine(info);
                                soundLine.open(audioFormat);
                    
                                FloatControl speedControl = (FloatControl) soundLine.getControl(FloatControl.Type.SAMPLE_RATE);
                    
                    
                                speedControl.setValue((float) (speedControl.getValue() * sampleChange));
                    
                                float speedControlVal = speedControl.getValue();
                     
                    
                                soundLine.start();
                                int nBytesRead = 0;
                                byte[] sampledData = new byte[BUFFER_SIZE];
                                while (nBytesRead != -1) {
                                    nBytesRead = audioInputStream.read(sampledData, 0, sampledData.length);
                                    if (nBytesRead >= 0) {
                    
                                        soundLine.write(sampledData, 0, nBytesRead);
                    
                                    }
                                }
                    
                                ais = new AudioInputStream(new ByteArrayInputStream(sampledData), audioFormatNew, (long) (sampledData * sampleChange));
                                System.out.println(audioFormatNew);
                                System.out.println("audio input stream initialised");
                                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                                System.out.println("byte output stream working");
                                AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("boo.wav"));
                                System.out.println("wrote to file:audio.write");
                                out.write(bos.toByteArray());
                            } catch (UnsupportedAudioFileException e) {
                                e.printStackTrace();
                            } finally {
                                if (audioInputStream != null) {
                                    audioInputStream.close();
                                }
                                if (out != null) {
                                    out.flush();
                                }
                    
                    
                            }
                    • 7. Re: FFT noise reduction problem
                      captfoss
                      I assume the issue deals with your use of fis.available()... you shouldn't ever use stream.available for anything.

                      You should use file2.getSize (or whatever it is that gives the length of the file)...
                      • 8. Re: FFT noise reduction problem
                        804900
                        captfoss wrote:
                        you shouldn't ever use stream.available for anything.
                        noted :)

                        have made changes as follows:
                                    FileInputStream fis = new FileInputStream(file2);
                        
                                    // AudioInputStream ais = new AudioInputStream(fis, audioFormatNew, (int) fis.available() / audioFormatNew.getFrameSize());
                                    AudioInputStream ais = new AudioInputStream(fis, audioFormatNew, (int) file2.length() / audioFormatNew.getFrameSize());
                                    int totalBytes = (int) (ais.getFrameLength() * ais.getFormat().getFrameSize());
                        
                                    //byte[] rawData = new byte[ais.available()];
                                    byte[] rawData = new byte[totalBytes];
                        
                                    ais.read(rawData);
                        but the problem still persists

                        i thought outputting the array would have been the easy part, but alas :(
                        • 9. Re: FFT noise reduction problem
                          captfoss
                          i thought outputting the array would have been the easy part, but alas :(
                          At this point, I'd assume the issue is probably your sample rate...
                          • 10. Re: FFT noise reduction problem
                            804900
                            Before I try to save it, I play the byte array with the SourceDataLine, and that plays all the sound. which is why i assumed the problem was with the saving.

                            **double message as firefox crashed and it had seemed message not sent**

                            Edited by: Fillis52 on 01-Nov-2010 14:35
                            • 11. Re: FFT noise reduction problem
                              804900
                              before sending to the output code, I play the byte array using a SourceDataLine, and the whole file is played. it's during saving that the half file becomes present, which is why i assumed it was an output problem
                              • 12. Re: FFT noise reduction problem
                                captfoss
                                Fillis52 wrote:
                                before sending to the output code, I play the byte array using a SourceDataLine, and the whole file is played. it's during saving that the half file becomes present, which is why i assumed it was an output problem
                                Upon looking at your code...
                                            byte[] sampledData = new byte[BUFFER_SIZE];
                                            while (nBytesRead != -1) {
                                                nBytesRead = audioInputStream.read(sampledData, 0, sampledData.length);
                                                if (nBytesRead >= 0) {
                                 
                                                    soundLine.write(sampledData, 0, nBytesRead);
                                 
                                                }
                                            }
                                This is perfectly fine code to play the file, but you can't then use sampledData to output the file... All you're going to have in the array is the last loop iteration, and you're not guaranteed that there's only one loop iteration...
                                • 13. Re: FFT noise reduction problem
                                  804900
                                  as playing the file is not the desired function of the system (its there so i can hear whats going on), would getting rid of the sourceDataLine.write and the if statement leave the byte array intact?
                                  • 14. Re: FFT noise reduction problem
                                    804900
                                    never mind. problem has been solved.

                                    as always it was a tiny error in variable initialisation that was the problem. I feel silly for not noticing it, but as least it means that the file output code is a stable as I originally thought

                                    thanks for your help! i think this thread can finally get closed!