Coverage Report - uk.co.javagear.NoiseGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
NoiseGenerator
0% 
0% 
3
 
 1  
 /*
 2  
  * NoiseGenerator.java
 3  
  *
 4  
  *  This file is part of JavaGear.
 5  
  *
 6  
  *  JavaGear is free software; you can redistribute it and/or modify
 7  
  *  it under the terms of the GNU General Public License as published by
 8  
  *  the Free Software Foundation; either version 2 of the License, or
 9  
  *  (at your option) any later version.
 10  
  *
 11  
  *  JavaGear is distributed in the hope that it will be useful,
 12  
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  
  *  GNU General Public License for more details.
 15  
  *
 16  
  *  You should have received a copy of the GNU General Public License
 17  
  *  along with JavaGear; if not, write to the Free Software
 18  
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  
  */
 20  
 
 21  
 package uk.co.javagear;
 22  
 
 23  
 /**
 24  
  * Texas SN76496 noise generator emulation.
 25  
  *
 26  
  * @author Copyright (C) 2002-2003 Chris White
 27  
  * @version 18th January 2003
 28  
  * @see "JavaGear Final Project Report"
 29  
  */
 30  
 public final class NoiseGenerator {
 31  
     
 32  0
     private static final int[] PARITY = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
 33  
     
 34  
     /**
 35  
      * Shift Register Reset Value SMS Specific (Bit 13).
 36  
      */
 37  
     private static final int RESET = 0x4000;
 38  
     
 39  
     /**
 40  
      * White Noise (values from Maxim).
 41  
      */
 42  
     private static final int WHITE_NOISE = 0x09;
 43  
     
 44  
     /**
 45  
      * Sync/Periodic Noise (values from Maxim).
 46  
      */
 47  
     private static final int SYNC_NOISE =  0x01;
 48  
     
 49  
     /**
 50  
      * Volume of channel.
 51  
      */
 52  
     private int volume;
 53  
     
 54  
     /**
 55  
      * Frequency of channel.
 56  
      */
 57  
     private int frequency;
 58  
     
 59  
     /**
 60  
      * First byte of frequency.
 61  
      */
 62  
     private int firstByte;
 63  
     
 64  
     /**
 65  
      * Counter for square waves.
 66  
      */
 67  
     private double counter;
 68  
     
 69  
     /**
 70  
      *  Positive/Negative output.
 71  
      */
 72  
     private boolean amplitudeFlipFlop;
 73  
     
 74  
     /**
 75  
      * PSG Cycles Per Sample.
 76  
      */
 77  
     private double psgCycles;
 78  
     
 79  
     /**
 80  
      * Channel Enabled.
 81  
      */
 82  
     private boolean enabled;
 83  
     
 84  
     /**
 85  
      * Noise Source.
 86  
      */
 87  
     private int shift;
 88  
     
 89  
     private int tappedBits;
 90  
     
 91  
     /**
 92  
      * Pointer to Noise.
 93  
      */
 94  
     private int noise;
 95  
     
 96  
     /**
 97  
      * Pointer to Channel 2 / Tone Generator 3.
 98  
      */
 99  
     private ToneGenerator chan2;
 100  
     
 101  
     /**
 102  
      * Use Channel 2's Frequency.
 103  
      */
 104  
     private boolean useChan2Freq;
 105  
     
 106  
     
 107  
     /**
 108  
      * NoiseGenerator Constructor.
 109  
      *
 110  
      * @param clockSpeed Clock Speed (Hz)
 111  
      * @param sampleRate Sample Rate (Hz)
 112  
      * @param t Pointer to Tone Generator
 113  
      */
 114  0
     public NoiseGenerator(double clockSpeed, int sampleRate, ToneGenerator t) {
 115  0
         this.chan2 = t;
 116  0
         psgCycles = (clockSpeed / sampleRate) * 2;
 117  0
         reset();
 118  0
     }
 119  
     
 120  
     
 121  
     /**
 122  
      * Reset Noise Generator to Default Values.
 123  
      */
 124  
     public void reset() {
 125  0
         tappedBits = WHITE_NOISE;
 126  0
         volume = 0x0F;
 127  0
         frequency = 1;
 128  0
         firstByte = 0;
 129  0
         counter = 0;
 130  0
         noise = RESET;
 131  0
         amplitudeFlipFlop = false;
 132  0
         useChan2Freq = false;
 133  0
         enabled = true;
 134  0
     }
 135  
     
 136  
     /**
 137  
      * Toggle channel On/Off.
 138  
      */
 139  
     public void setEnabled() {
 140  0
         enabled = !enabled;
 141  0
     }
 142  
     
 143  
     /**
 144  
      * Set channel frequency.
 145  
      *
 146  
      * @param f frequency.
 147  
      */
 148  
     public void setFrequency(int f) {
 149  
         // Bit 2 Selects White/Sync noise
 150  0
         if ((f & 0x04) == 0x04) {
 151  0
             tappedBits = WHITE_NOISE;
 152  
         } else {
 153  0
             tappedBits = SYNC_NOISE;
 154  
         }
 155  
         
 156  
         // Reset shift register to preset
 157  0
         shift = RESET;
 158  
         
 159  0
         switch(f & 0x03) {
 160  
             case 0x00:
 161  0
                 frequency = 0x10; // 16
 162  0
                 useChan2Freq = false;
 163  0
                 break;
 164  
             case 0x01:
 165  0
                 frequency = 0x20; // 32
 166  0
                 useChan2Freq = false;
 167  0
                 break;
 168  
             case 0x02:
 169  0
                 frequency = 0x40; // 64
 170  0
                 useChan2Freq = false;
 171  0
                 break;
 172  
                 // Channel 2 Frequency
 173  
             case 0x03:
 174  0
                 frequency = chan2.getFrequency();
 175  0
                 useChan2Freq = true;
 176  0
                 break;
 177  
             default:
 178  
                 break;
 179  
         }
 180  0
     }
 181  
     
 182  
     
 183  
     /**
 184  
      * Return a single sample from noise generator.
 185  
      *
 186  
      * @return sample (0 to +15)
 187  
      */
 188  
     public int getSample() {
 189  0
         if (!enabled) {
 190  0
             return 0;
 191  
         }
 192  
         
 193  
         // Decrement Counter
 194  0
         counter -= psgCycles;
 195  
         
 196  
         // Counter Expired
 197  0
         if (counter < 0) {
 198  
             // Toggle Amplitude Flip Flop
 199  0
             amplitudeFlipFlop = !amplitudeFlipFlop;
 200  
             
 201  
             // Update Frequency from Channel 2
 202  0
             if (useChan2Freq) {
 203  0
                 frequency = chan2.getFrequency();
 204  
             }
 205  
             
 206  
             // Reload counter
 207  0
             while (counter < 0) {
 208  0
                 if (frequency > 0) {
 209  0
                     counter += frequency;
 210  
                 } else {
 211  0
                     counter = 1; // so we don't get stuck in an endless loop
 212  
                 }
 213  
             }
 214  
             
 215  
             // We only want to do this once per cycle
 216  0
             if (amplitudeFlipFlop) {
 217  0
                 shift = (shift >> 1) | (PARITY[(shift & tappedBits) & 0x0F] << 15);
 218  
             }
 219  
         }
 220  
         
 221  0
         if ((shift & 0x01) == 0x00) {
 222  0
             return 0; // Noise channel does not output negative values
 223  
         } else {
 224  0
             return (15 - (volume & 0x0f)); // ie 0 is 15, 1 is 14 etc
 225  
         }
 226  
     }
 227  
     
 228  
     /**
 229  
      * Returns the value of property <code>volume</code>. The channel's volume.
 230  
      *
 231  
      * @return the value of property <code>volume</code>. The channel's volume.
 232  
      */
 233  
     public int getVolume() {
 234  0
         return this.volume;
 235  
     }
 236  
     
 237  
     /**
 238  
      * Sets the value of property <code>volume</code>. The channel's volume.
 239  
      *
 240  
      * @param volume the new value of property <code>volume</code>.
 241  
      */
 242  
     public void setVolume(int volume) {
 243  0
         this.volume = volume;
 244  0
     }
 245  
     
 246  
 }