Changeset 85e0208 in orbit for android/src/info/puzzlebox/orbit


Ignore:
Timestamp:
12/19/12 09:04:54 (10 years ago)
Author:
AzureViolin <zhanghaotz@…>
Branches:
master, RawEEG, Raw_EEG_Plot, Servo, Tab_Interface, pyramid
Children:
d604d68
Parents:
42379ae
Message:

Android can now generate fly control command on the fly. With a whole lot of bugs, the screen will freeze when tap 'Manual Control'

File:
1 edited

Legend:

Unmodified
Added
Removed
  • android/src/info/puzzlebox/orbit/MainActivity.java

    r12a6a71 r85e0208  
    1515 */ 
    1616 
     17 
     18 
    1719//import java.io.IOException; 
    1820//import java.util.ArrayList; 
    19 //import java.util.Arrays; 
     21//import java.util.Arrays; /** should import java.util.Arrays if want to use concatFloatAll*/ 
    2022//import java.util.Set; 
    2123//import java.util.concurrent.ExecutorService; 
     
    6365         * UI 
    6466         */ 
     67 
     68        /** 
     69         *  
     70         */ 
    6571        ProgressBar progressBarAttention; 
    6672        ProgressBar progressBarMeditation; 
     
    6975        SeekBar seekBarAttention; 
    7076        SeekBar seekBarMeditation; 
     77        SeekBar seekBarThrottle; 
     78        //SeekBar seekBarPitch; 
     79        //SeekBar seekBarYaw; 
     80         
    7181        TextView tv; 
    7282        Button b; 
     
    8898         * will be generated on-the-fly. This conversion process is already underway 
    8999         */ 
    90         int audioFile = R.raw.throttle_hover_android_common; 
     100        //int audioFile = R.raw.throttle_hover_android_common; 
    91101        //      int audioFile = R.raw.throttle_hover_android_htc_one_x; 
    92102 
     
    220230                seekBarMeditation = (SeekBar)findViewById(R.id.seekBarMeditation); 
    221231                seekBarMeditation.setOnSeekBarChangeListener(this); 
    222  
     232                seekBarThrottle = (SeekBar)findViewById(R.id.seekBarThrottle); 
     233                seekBarThrottle.setOnSeekBarChangeListener(this); 
     234                 
    223235                tv = (TextView)findViewById(R.id.textViewDebugConsole); 
    224236                tv.setMovementMethod(new ScrollingMovementMethod()); 
     
    247259                        } 
    248260                }); 
    249                 soundID = soundPool.load(this, audioFile, 1); 
     261                //soundID = soundPool.load(this, audioFile, 1); 
    250262 
    251263                //              genTone(); 
     
    947959 
    948960        } // demoMode 
    949  
     961         
     962         
     963        public void manualMode(View view) { 
     964 
     965                /** 
     966                 * Manual mode is called when the "Manual Control" button is pressed. 
     967                 */ 
     968 
     969                Log.v(TAG, "Launch Helicopter Manual Control Mode"); 
     970                appendTextAndScroll("Launch Helicopter Manual Control Mode\n"); 
     971 
     972                manualControl(); 
     973 
     974        } // demoMode 
     975         
     976 
     977        public static final int samplePerSecond = 44100; 
     978        final double sampleTime = 1/(double)samplePerSecond; 
     979         
     980        final double longHIGH = 0.000875-sampleTime*2;//half period HIGH of code '1', in s 
     981        final double longLOW = 0.000729+sampleTime*3; 
     982        final double shortHIGH = 0.000458-sampleTime*2; 
     983        final double shortLOW = 0.000333+sampleTime*2; 
     984         
     985        final float[] waveLongHIGH=halfSineGen('u',longHIGH,samplePerSecond); 
     986        final float[] waveLongLOW=halfSineGen('d',longLOW,samplePerSecond); 
     987        final float[] waveShortHIGH=halfSineGen('u',shortHIGH,samplePerSecond); 
     988        final float[] waveShortLOW=halfSineGen('d',shortLOW,samplePerSecond); 
     989        final float[] waveBit[]= {concatFloat(waveShortHIGH,waveShortLOW),concatFloat(waveLongHIGH,waveLongLOW)}; 
     990 
     991         
     992        public void manualControl() { 
     993                /**  
     994                 * Dynamically Generate Audio Control signal through Audio Jack, can be controlled with Throttle Seek Bar. 
     995                 */ 
     996/*reference 
     997                /** Getting the user sound settings  
     998                AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); 
     999                float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
     1000                float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 
     1001                float volume = actualVolume / maxVolume; 
     1002                /** Is the sound loaded already?  
     1003                if (loaded) { 
     1004                        soundPool.play(soundID, volume, volume, 1, 0, 1f); 
     1005                        if (DEBUG) 
     1006                                Log.v(TAG, "Played sound"); 
     1007                } 
     1008                */ 
     1009                AndroidAudioDevice device = new AndroidAudioDevice(); 
     1010 
     1011                for (int j = 0; j<4; j++) 
     1012                        device.writeSamples(code2wave(command2code(80,78,31,'A'),samplePerSecond,false));                
     1013                 
     1014                device.writeSamples(initialWave(samplePerSecond,false)); 
     1015                                 
     1016                for (int j = 0; j<50; j++){ 
     1017                        device.writeSamples(code2wave(command2code(80,78,31,'A'),samplePerSecond,false));                
     1018                         
     1019                        /*try{ 
     1020                                Thread.sleep(80); 
     1021                        } catch (InterruptedException e){ 
     1022                                e.printStackTrace(); 
     1023                        }*/ 
     1024                } 
     1025        } 
     1026         
     1027        /** 
     1028         * command2code, turn throttle, pitch and yaw to IR code (in sound data form). 
     1029         * @param throttle: 0~127, nothing will happen if this value is below 30. 
     1030         * @param yaw: 0~127, normally 78 will keep orbit from rotating. 
     1031         * @param pitch: 0~63, normally 31 will stop the top propeller. 
     1032         * @param channel: 'A' or 'B' or 'C', depend on which channel you want to pair to the orbit. You can fly at most 3 orbit in a same room.  
     1033         * @return 
     1034         */ 
     1035         
     1036        int command2code(int throttle, int yaw, int pitch, char channel){ 
     1037                int code = throttle << 21; 
     1038                code += 1 << 20 ; 
     1039                code += yaw << 12; 
     1040                code += pitch << 4 ; 
     1041        //  weird, if use int code= throttle << 21 + 1<<20 + yaw <<12 +pitch<<4; it won't work. 
     1042                switch (channel){ 
     1043                        case 'A':       code += 1 << 11; 
     1044                                                break; 
     1045                //      case 'B':       break; 
     1046                        case 'C':       code += 1 << 19; 
     1047                                                break; 
     1048                        default:        break; 
     1049                } 
     1050                int checkSum=0; 
     1051                        for (int i=0; i<7; i++) 
     1052                                checkSum += (code >> 4*i) & 15; //15=0x0F=0b00001111 
     1053                checkSum = 16-(checkSum & 15); 
     1054                return code + checkSum; 
     1055        } 
     1056         
     1057        /** code2wave(,,) 
     1058         * generate 1 full fly command in wave form on the fly. 
     1059         * @param code: the control code array need to be turned into  
     1060         * @param sampleRate: sample rate supported on certain Android device, normally 44100, but on some device it is 48000. 
     1061         * @param flip: on certain Android device, the signal need to be flipped. true means flip, false means not. 
     1062         * @return fully assembled fly command in a float array, to be written in buffer and sent out. 
     1063         */ 
     1064         
     1065        float[] code2wave(int code, int sampleRate, boolean flip){ 
     1066 
     1067                //float[] wave = concatFloat(concatFloat(waveLongLOW,concatFloat(waveLongHIGH,waveShortLOW)),concatFloat(waveLongHIGH,waveShortLOW)); 
     1068                /* 
     1069                final double longHIGH = 0.000875-sampleTime*2;//half period HIGH of code '1', in s 
     1070                final double longLOW = 0.000729+sampleTime*5; 
     1071                final double shortHIGH = 0.000458-sampleTime*3; 
     1072                final double shortLOW = 0.000333+sampleTime*3; 
     1073                */ 
     1074                float[] wave = halfSineGen('d',longLOW,sampleRate); 
     1075                float[] tempWave = concatFloat(halfSineGen('u',longHIGH-sampleTime*2,sampleRate),halfSineGen('d',shortLOW+sampleTime*2,sampleRate)); 
     1076                wave = concatFloat(wave,tempWave); 
     1077                wave = concatFloat(wave,tempWave); 
     1078                /*int waveLength = waveLongLOW.length+(waveLongHIGH.length+waveShortLOW.length)*2; 
     1079                         
     1080                byte sum=0; 
     1081                for (int i=0; i<28; i++){ 
     1082                        sum += (code >>> i) & 1) 
     1083                } 
     1084                waveLength+=sum*(waveLongHIGH.length+waveLongLOW.length)+(28-sum)*(waveShortHIGH.length+waveShortLOW.length); 
     1085                waveLength+=waveLongHIGH.length; 
     1086                 
     1087                float[] wave=new float[waveLength]; 
     1088                */ 
     1089                 
     1090                for (int i=27; i>=0; i--)  
     1091                        wave=concatFloat(wave,waveBit[((code >>> i) & 1)]); 
     1092                                 
     1093                wave=concatFloat(wave,waveLongHIGH); 
     1094                //float[] zeroArray= new float[1024]; 
     1095                 
     1096                if (flip) 
     1097                        for (int i=0; i<wave.length; i++) 
     1098                                wave[i]=-wave[i]; 
     1099                 
     1100                wave=concatFloat(wave,new float[4096]); 
     1101                 
     1102                        return wave; 
     1103        } 
     1104         
     1105        /* 
     1106        float[] zerosFloat(int num){ 
     1107                return  new float[num]; 
     1108        } 
     1109        */ 
     1110         
     1111        /* 
     1112        float[] bitGen(short bit, int sampleRate){ 
     1113 
     1114                if (bit == 0)  
     1115                        return concatFloat(waveShortHIGH,waveShortLOW); 
     1116                else  
     1117                        return concatFloat(waveLongHIGH,waveLongLOW); 
     1118        } 
     1119*/ 
     1120         
     1121        float[] initialWave(int sampleRate, boolean flip){ 
     1122                final double initLongHIGH=0.001-sampleTime*1; //seconds 
     1123                final double initLongZERO=0.002+sampleTime*1; 
     1124                final double initMediumLOW=0.0005-sampleTime*1; 
     1125                final double initShortHIGH=0.0001+sampleTime*1; 
     1126                final double initShortLOW=0.00018; 
     1127                final double initPause=0.010; 
     1128                final double initSpace=0.084354; 
     1129                 
     1130                final float[] waveInitLongHIGH=halfSineGen('u',initLongHIGH,sampleRate); 
     1131                final int waveInitLongZEROLength= (int)Math.floor(initLongZERO*sampleRate); 
     1132                final float[] waveInitMediumLOW=halfSineGen('d',initMediumLOW,sampleRate); 
     1133                final float[] waveInitShortHIGH=halfSineGen('u',initShortHIGH,sampleRate); 
     1134                final float[] waveInitShortLOW=halfSineGen('d',initShortLOW,sampleRate); 
     1135                                 
     1136                final float[] waveLongHLongZERO= concatFloat(waveInitLongHIGH,new float[waveInitLongZEROLength]); 
     1137                final float[] waveMediumLShortH = concatFloat(waveInitMediumLOW,waveInitShortHIGH); 
     1138                final float[] waveShortHShortL = concatFloat(waveInitShortHIGH, waveInitShortLOW); 
     1139                 
     1140                float[] initWaveOriginal = concatFloat(waveLongHLongZERO,waveLongHLongZERO); 
     1141                initWaveOriginal = concatFloat(initWaveOriginal,waveInitLongHIGH); 
     1142                initWaveOriginal = concatFloat(initWaveOriginal, waveMediumLShortH); 
     1143                 
     1144                float[] initWave123 = concatFloat(initWaveOriginal,waveInitMediumLOW); 
     1145                float[] initWave456 = concatFloat(initWaveOriginal,waveInitShortLOW); 
     1146                 
     1147                for (int i=0; i<4; i++){ 
     1148                        initWave123 = concatFloat(initWave123,waveShortHShortL); 
     1149                        initWave456 = concatFloat(initWave456,waveShortHShortL); 
     1150                } 
     1151                 
     1152                initWave123 = concatFloat(initWave123,waveInitShortHIGH); 
     1153                initWave123 = concatFloat(initWave123,waveMediumLShortH); 
     1154                 
     1155                initWave456 = concatFloat(initWave456,waveInitShortHIGH); 
     1156                initWave456 = concatFloat(initWave456,waveMediumLShortH); 
     1157                 
     1158                if (flip){ 
     1159                        for (int i=0; i<initWave123.length; i++) 
     1160                                initWave123[i]=-initWave123[i]; 
     1161                         
     1162                        for (int i=0; i<initWave456.length; i++) 
     1163                                initWave456[i]=-initWave456[i]; 
     1164                } 
     1165                 
     1166                 
     1167                int initPauseInSamples=(int)Math.floor(initPause*sampleRate); 
     1168                initWave123 = concatFloat(initWave123,new float[initPauseInSamples]); 
     1169                initWave456 = concatFloat(initWave456,new float[initPauseInSamples]); 
     1170                 
     1171                float[] initWave123Pattern=initWave123; 
     1172                float[] initWave456Pattern=initWave456; 
     1173                 
     1174                 
     1175                for (int i=0; i<2; i++){ 
     1176                        initWave123 = concatFloat(initWave123, initWave123Pattern); 
     1177                        initWave456 = concatFloat(initWave456, initWave456Pattern); 
     1178                } 
     1179                 
     1180                return concatFloat(initWave123,initWave456); 
     1181                 
     1182        } 
     1183         
     1184        /** concatFloatAll 
     1185         * since Arrays.copyOf is added in API level 9, 
     1186         * so this not compatible with API level < 9, or known as Android 2.3    *  
     1187         * @param arbitrary numbers of arrays that you want to connect together  
     1188         * @return one array that contains all the parameters in a single array. 
     1189         */ 
     1190         
     1191        /* 
     1192        public float[] concatFloatAll(float[] first, float[]... rest) { 
     1193                int totalLength = first.length; 
     1194                for (float[] array : rest) { 
     1195                        totalLength += array.length; 
     1196                } 
     1197                float[] result= Arrays.copyOf(first, totalLength); 
     1198                int offset = first.length; 
     1199                for (float[] array : rest){ 
     1200                        System.arraycopy(array, 0, result, offset, array.length); 
     1201                        offset += array.length; 
     1202                } 
     1203                return result; 
     1204        } 
     1205        */ 
     1206         
     1207        public float[] concatFloat(float[] A, float[] B){ 
     1208                float[] C = new float[A.length+B.length]; 
     1209                System.arraycopy(A, 0, C, 0, A.length); 
     1210                System.arraycopy(B, 0, C, A.length, B.length); 
     1211                return C; 
     1212        } 
     1213         
     1214        float[] halfSineGen(char dir,double halfPeriod, int sampleRate) { 
     1215                int halfPeriodInSamples = (int)Math.floor(halfPeriod*sampleRate); 
     1216                float halfSine[] = new float[halfPeriodInSamples]; 
     1217                double increment = Math.PI/(halfPeriod*sampleRate); 
     1218                double angle = 0; 
     1219                 
     1220                if (dir == 'u') 
     1221                        for (int i =0; i<halfPeriodInSamples;i++) 
     1222                        { 
     1223                        halfSine[i]=(float)Math.sin(angle); 
     1224                        angle += increment; 
     1225                        } 
     1226                else if (dir == 'd'){ 
     1227                        angle = Math.PI; 
     1228                        for (int i =0; i<halfPeriodInSamples;i++) 
     1229                        { 
     1230                        halfSine[i]=(float)Math.sin(angle); 
     1231                        angle += increment; 
     1232                        } 
     1233                } 
     1234                 
     1235                return halfSine; 
     1236        } 
    9501237 
    9511238} // MainActivity 
     1239 
     1240 
     1241class AndroidAudioDevice { 
     1242        AudioTrack track; 
     1243        short[] buffer = new short[6144]; 
     1244         
     1245        public AndroidAudioDevice() 
     1246        { 
     1247                int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT); 
     1248                track = new AudioTrack(AudioManager.STREAM_MUSIC,44100,AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT,minSize, AudioTrack.MODE_STREAM); 
     1249                track.play(); 
     1250        } 
     1251         
     1252        public void writeSamples(float[] samples) 
     1253        { 
     1254                fillBuffer(samples); 
     1255                track.write(buffer,0,2*samples.length); 
     1256        } 
     1257         
     1258        private void fillBuffer(float[] samples) 
     1259        { 
     1260                if(buffer.length < 2*samples.length) 
     1261                        buffer=new short[2*samples.length]; 
     1262                 
     1263                float increment = (float)((2*Math.PI)*500/MainActivity.samplePerSecond); 
     1264                float angle = 0; 
     1265                 
     1266                for (int i=0; i< samples.length; i++){ 
     1267                        buffer[2*i+1]=(short)(Math.sin(angle)*Short.MAX_VALUE); 
     1268                        buffer[2*i]=(short)(samples[i]*Short.MAX_VALUE); 
     1269                        angle += increment; 
     1270                } 
     1271        } 
     1272        public void releasetrack(){ 
     1273                track.release(); 
     1274        } 
     1275} 
Note: See TracChangeset for help on using the changeset viewer.