Commit b2a15e7a authored by hanriaca's avatar hanriaca Committed by CallisteHanriat

tmp : adding saveCurrentState function into respeaking mode

fix progressBar / textviews when  we save a session for check mode

Adding modifications to sharedPreferences

tmp push to work this week end

save current session for respeaking mode

adding smapleRate into sharedPreferencesobject + better organisation of code

Tmp commit to get the code at home

last modifs

Save elicitation session works + save respeaking session.

tmp commit

Respeak + RecordEliciton savingcurrent state works. More modularity thanks to divide the code inside smaller functions
parent bb8131e5
......@@ -22,7 +22,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:drawableLeft="@drawable/ic_undo_black_24dp"
android:onClick="onBackPressed"
android:onClick="onButtonBackPressed"
android:text="@string/goBack"
android:textColor="#D32F2F"
android:layout_marginBottom="20dp"
......
......@@ -121,5 +121,20 @@
<string name="sessionCheckExportFile">checkExportFile</string>
<string name="sessionInputFile">inputFile</string>
<string name="mexico">Ex : Mexico</string>
<string name="sessionOutputFile">session_output_file</string>
<string name="sessionSelectedMode">selected_mode</string>
<string name="randomUUID">random_uuid</string>
<string name="dirname">dirname</string>
<string name="rewindAmount">rewindAmount</string>
<string name="languageCode">LanguageCode</string>
<string name="languageName">languageName</string>
<string name="languageMotherCode">languageMotherCode</string>
<string name="languageMotherName">languageMotherName</string>
<string name="serializedMapper">serializedMapper</string>
<string name="totalAudioLength">totalAutioLength</string>
<string name="payLoadSize">payLoadaSize</string>
<string name="currentPCMSample">currentPCMSample</string>
<string name="sampleRate">sampleRate</string>
<string name="currentLine">currentLine</string>
<string name="recordDuration">duration</string>
</resources>
......@@ -222,7 +222,11 @@ public class ModeSelection extends Activity implements OnClickListener{
intent = new Intent(getActivity(), CheckTranscription.class);
} else if (mode.compareToIgnoreCase(CheckWordVariant.TAG) == 0) {
intent = new Intent(getActivity(), CheckWordVariant.class);
} else {
} else if (mode.compareToIgnoreCase(ThumbRespeakActivityLig.TAG) == 0) {
intent = new Intent(getActivity(), ThumbRespeakActivityLig.class);
} else if (mode.compareToIgnoreCase(RecordElicitation.TAG) == 0) {
intent = new Intent(getActivity(), RecordElicitation.class);
}else {
Toast.makeText(getActivity(), "An error ocurred, the session could not be retrieved", Toast.LENGTH_LONG).show();
return;
}
......@@ -272,7 +276,7 @@ public class ModeSelection extends Activity implements OnClickListener{
((TextView) ll.findViewById(R.id.session_date)).setText(prefsUserSession.getString(getString(R.string.sessionDate), "undefined"));
}
((TextView) ll.findViewById(R.id.session_progress)).setText("" + prefsUserSession.getInt(getString(R.string.sessionProgress), 0));
((TextView) ll.findViewById(R.id.session_progress)).setText("" + prefsUserSession.getString(getString(R.string.sessionProgress), "0"));
// display only filename
String file = new File(prefsUserSession.getString(getString(R.string.sessionInputFile), "undefined")).getName();
......
......@@ -6,7 +6,12 @@ package org.lp20.aikuma.audio.record;
import android.util.Log;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.UUID;
import org.lp20.aikuma.audio.Sampler;
......@@ -21,11 +26,13 @@ import org.lp20.aikuma.model.Recording;
* @author Oliver Adams <oliver.adams@gmail.com>
* @author Florian Hanke <florian.hanke@gmail.com>
*/
public class Mapper {
public class Mapper implements Serializable {
/** The segment mapping between the original and the respeaking. */
private Segments segments;
private BufferedReader reader;
/**
* Temporarily store the boundaries of segments before being put in
* segments */
......@@ -45,6 +52,16 @@ public class Mapper {
public Mapper(UUID uuid) {
this.segments = new Segments();
this.mappingFile = new File(Recording.getNoSyncRecordingsPath(), uuid + ".map");
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(this.mappingFile)));
restoreFromMappingFile();
Log.d("mapper generation", "yes");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public File getMapFile() {
......@@ -77,6 +94,24 @@ public class Mapper {
return 0L;
}
}
private void restoreFromMappingFile() throws IOException {
String line;
while ((line = reader.readLine()) != null && (line.isEmpty() || line.split(":").length <= 1)) { continue; }
Log.d("line", line);
do {
String[] pair = line.split(":");
String[] strFirstSeg = pair[0].split(",");
String[] strSecondSeg = pair[1].split(",");
Segment original = new Segment(Long.parseLong(strFirstSeg[0]), Long.parseLong(strFirstSeg[1]));
Log.d("original seg ", original.getStartSample() + " -> " + original.getEndSample());
Segment rspkSeg = new Segment(Long.parseLong(strSecondSeg[0]), Long.parseLong(strSecondSeg[1]));
Log.d("rspkSeg seg ", rspkSeg.getStartSample() + " -> " + rspkSeg.getEndSample());
segments.put(original, rspkSeg);
Log.d("segments size", ""+segments.getSegmentMap().size());
originalStartOfSegment = original.getEndSample();
} while((line = reader.readLine()) != null && !line.isEmpty() && line.split(":").length > 1);
}
/**
* Marks the start of an original segment.
......@@ -89,6 +124,7 @@ public class Mapper {
// originalStartOfSegment
if (originalEndOfSegment != null) {
originalStartOfSegment = original.getCurrentSample();
Log.d("mark", "mark original segment : " + original.getCurrentSample());
}
}
......
......@@ -95,6 +95,25 @@ public class PCMWriter implements Sampler {
return this.fullFilename;
}
public int getPayloadSize() {
return payloadSize;
}
public void setPayloadSize(int payloadSize) {
this.payloadSize = payloadSize;
}
public void setCurrentSample(long currentSample) {
this.currentSample = currentSample;
}
public RandomAccessFile getRandomAccessWriter() {
return randomAccessWriter;
}
/**
* Write the given byte buffer to the file.
*
......@@ -111,6 +130,7 @@ public class PCMWriter implements Sampler {
// Remember larger payload.
//
payloadSize += buffer.length;
Log.d("payLoadSize", "payLoadSize = " + payloadSize);
} catch (IOException e) {
Log.e(PCMWriter.class.getName(),
"Error occured in updateListener, recording is aborted");
......@@ -118,6 +138,7 @@ public class PCMWriter implements Sampler {
if (sampleSize == 16) {
this.currentSample += buffer.length / 2;
Log.d("currentSaple", "currentSample = " + this.currentSample);
} else {
//Assume sample size is 8.
this.currentSample += buffer.length;
......@@ -141,15 +162,12 @@ public class PCMWriter implements Sampler {
*/
public void write(short[] buffer, int len) {
byte[] byteBuffer = new byte[len * 2];
for (int i = 0; i < len; i++) {
short sample = buffer[i];
// TODO Use Java helpers?
byteBuffer[i * 2] = (byte) sample;
byteBuffer[i * 2 + 1] = (byte) (sample >>> 8);
}
write(byteBuffer);
}
......@@ -230,70 +248,82 @@ public class PCMWriter implements Sampler {
*/
public void prepare(String fullFilename) {
this.fullFilename = fullFilename;
Log.d("targetFileName", "targetFileName = " + fullFilename);
try {
File f = new File(fullFilename);
Boolean exists = f.exists();
/*if (exists && fullFilename.contains("no-sync")) {
String[] p2 = fullFilename.split(".wav");
fullFilename = p2[0]+"(1)"+p2[1];
Log.d("new full", "targetFileName => "+fullFilename);
}*/
createRandomAccessFile(fullFilename);
// Write the full WAV PCM file header.
//
// Set file length to 0, to prevent unexpected
// behaviour in case the file already existed.
//
randomAccessWriter.setLength(0);
// "RIFF" announcement.
//
randomAccessWriter.writeBytes("RIFF");
// File size, 0 = unknown.
//
randomAccessWriter.writeInt(0);
// "WAVE fmt " = WAV format.
//
randomAccessWriter.writeBytes("WAVE");
randomAccessWriter.writeBytes("fmt ");
// Sub-chunk size, 16 = PCM.
//
randomAccessWriter.writeInt(Integer.reverseBytes(16));
// AudioFormat, 1 = PCM.
//
randomAccessWriter.writeShort(Short.reverseBytes((short) 1));
// Number of channels, 1 = mono, 2 = stereo.
//
randomAccessWriter.writeShort(
Short.reverseBytes(numberOfChannels));
// Sample rate.
//
randomAccessWriter.writeInt(Integer.reverseBytes(sampleRate));
// Byte rate = SampleRate * NumberOfChannels * BitsPerSample / 8.
//
randomAccessWriter.writeInt(Integer.reverseBytes(sampleRate
* sampleSize * numberOfChannels / 8));
// Block align = NumberOfChannels * BitsPerSample / 8.
//
randomAccessWriter.writeShort(Short .reverseBytes(
(short) (numberOfChannels * sampleSize / 8)));
// Bits per sample.
//
randomAccessWriter.writeShort(Short.reverseBytes(sampleSize));
// "data" announcement.
//
randomAccessWriter.writeBytes("data");
// Data chunk size, 0 = unknown.
//
randomAccessWriter.writeInt(0);
if (!exists) {
randomAccessWriter.setLength(0);
Log.d("passage", "targetFileName passage here for " + fullFilename);
// "RIFF" announcement.
//
randomAccessWriter.writeBytes("RIFF");
// File size, 0 = unknown.
//
randomAccessWriter.writeInt(0);
// "WAVE fmt " = WAV format.
//
randomAccessWriter.writeBytes("WAVE");
randomAccessWriter.writeBytes("fmt ");
// Sub-chunk size, 16 = PCM.
//
randomAccessWriter.writeInt(Integer.reverseBytes(16));
// AudioFormat, 1 = PCM.
//
randomAccessWriter.writeShort(Short.reverseBytes((short) 1));
// Number of channels, 1 = mono, 2 = stereo.
//
randomAccessWriter.writeShort(
Short.reverseBytes(numberOfChannels));
// Sample rate.
//
randomAccessWriter.writeInt(Integer.reverseBytes(sampleRate));
// Byte rate = SampleRate * NumberOfChannels * BitsPerSample / 8.
//
randomAccessWriter.writeInt(Integer.reverseBytes(sampleRate
* sampleSize * numberOfChannels / 8));
// Block align = NumberOfChannels * BitsPerSample / 8.
//
randomAccessWriter.writeShort(Short .reverseBytes(
(short) (numberOfChannels * sampleSize / 8)));
// Bits per sample.
//
randomAccessWriter.writeShort(Short.reverseBytes(sampleSize));
// "data" announcement.
//
randomAccessWriter.writeBytes("data");
// Data chunk size, 0 = unknown.
//
randomAccessWriter.writeInt(0);
}
// Clear the byte array.
//
// Note: Removed but here for inspiration.
......
......@@ -50,6 +50,7 @@ public class Recorder implements AudioHandler, MicrophoneListener, Sampler {
*/
public Recorder(int type, File path, long sampleRate) throws MicException {
this(type, path, sampleRate, new SimpleAnalyzer());
Log.d("Recorder", "filePath : " + path.getAbsolutePath());
}
/**
......@@ -258,14 +259,12 @@ public class Recorder implements AudioHandler, MicrophoneListener, Sampler {
*/
public void save() {
file.write(audioBuffer, audioBufLength);
totalAudioLength += audioBufLength;
if (this.type == 0 &&
Math.round((double) totalAudioLength / sampleRate) < Recording.SAMPLE_SEC) // 15sec sample
{
sampleFile.write(audioBuffer, audioBufLength);
}
audioBufLength = 0;
}
......@@ -324,7 +323,25 @@ public class Recorder implements AudioHandler, MicrophoneListener, Sampler {
{
sampleFile.write(buffer);
}
}
public long getTotalAudioLength() {
return totalAudioLength;
}
public void setTotalAudioLength(long totalAudioLength) {
this.totalAudioLength = totalAudioLength;
}
public PCMWriter getFile() {
return file;
}
public void setFile(PCMWriter file) {
this.file = file;
}
/**
......
......@@ -91,6 +91,7 @@ public class ThumbRespeaker {
break;
case 1: //Rewind and record the start-sample in mapper
player.seekToSample(mapper.getOriginalStartSample());
Log.d("original sample", "get original start sample : " + mapper.getOriginalStartSample());
mapper.markOriginal(player);
player.rewind(rewindAmount);
break;
......@@ -98,7 +99,9 @@ public class ThumbRespeaker {
player.seekToSample(previousEndSample);
break;
}
Log.d("previousEndSample", "previousEndSample -> " + previousEndSample/getSimplePlayer().getSampleRate());
previousEndSample = player.getCurrentSample();
Log.d("previousEndSample", "previousEndSampleAfter -> " + previousEndSample/getSimplePlayer().getSampleRate());
player.play();
}
......@@ -145,10 +148,19 @@ public class ThumbRespeaker {
// Because of rewind after each respeaking-segment,
// Force user to record respeaking after listening next original-segment
if(player.getCurrentSample() > mapper.getOriginalStartSample()) {
mapper.store(player, recorder);
Log.d("save map file", "save map file at " + mapper.getMapFile().getAbsolutePath());
mapper.store(player, recorder);
}
}
public long getPreviousEndSample() {
return previousEndSample;
}
public void setPreviousEndSample(long previousEndSample) {
this.previousEndSample = previousEndSample;
}
/**
* Stops/finishes the respeaking process
*
......@@ -170,6 +182,13 @@ public class ThumbRespeaker {
return recorder.getCurrentMsec();
}
/**
* read the mapping file and create segments.
*/
public void restoreMapper() {
}
/**
* finishedPlaying accessor
*
......@@ -198,6 +217,11 @@ public class ThumbRespeaker {
return this.player;
}
public void setMapper(Mapper mapper) {
this.mapper = mapper;
}
/**
* Releases the resources associated with this respeaker.
*/
......
......@@ -114,5 +114,11 @@ public class MetadataSession {
private void setSpeakerGender(int g) {
speakerGender = g;
}
public String toString() {
return "name : " + getSpeakerName() + " age : " + getSpeakerAge() + "speaker gender : " + getSpeakerGender() +
" region origin : " + getRegionOrigin() + " record lang : "+ getRecordLanguage().getName() +
" mother tongue : " + getMotherTongue().getName() + " rspk languages : " + getExtraLanguages().toString();
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lp20.aikuma.model;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ClassLoaderObjectInputStream;
import org.apache.commons.net.util.Base64;
public class ObjectSerializer {
public static String serialize(Serializable obj) throws IOException {
if (obj == null)
return "";
try {
ByteArrayOutputStream serialObj = new ByteArrayOutputStream();
Deflater def = new Deflater(Deflater.BEST_COMPRESSION);
ObjectOutputStream objStream = new ObjectOutputStream(new DeflaterOutputStream(
serialObj, def));
objStream.writeObject(obj);
objStream.close();
return encodeBytes(serialObj.toByteArray());
} catch (Exception e) {
throw new IOException("Serialization error: " + e.getMessage(), e);
}
}
public static Object deserialize(String str) throws IOException {
if (str == null || str.length() == 0)
return null;
ObjectInputStream objStream = null;
try {
ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str));
objStream = new ClassLoaderObjectInputStream(Thread.currentThread().getContextClassLoader(), new InflaterInputStream(serialObj));
return objStream.readObject();
} catch (Exception e) {
throw new IOException("Deserialization error: " + e.getMessage(), e);
} finally {
IOUtils.closeQuietly(objStream);
}
}
public static String encodeBytes(byte[] bytes) throws UnsupportedEncodingException {
return bytes == null ? null : new String(Base64.encodeBase64(bytes), Charset.forName("UTF-8"));
}
public static byte[] decodeBytes(String str) throws UnsupportedEncodingException {
return Base64.decodeBase64(str.getBytes(Charset.forName("UTF-8")));
}
}
......@@ -83,6 +83,8 @@ public class Recording extends FileModel {
int bitsPerSample, Double latitude, Double longitude) {
super(versionName, ownerId, null, null, format);
Log.d("UUID", "UUID on constructor : "+ recordingUUID.toString());
Log.d("id", "respeakingID : " + respeakingId);
this.recordingUUID = recordingUUID;
setName(name);
setDate(date);
......@@ -103,6 +105,14 @@ public class Recording extends FileModel {
setFileType(sourceVerId, languages);
}
public void setRecordingUUID(UUID recordingUUID) {
this.recordingUUID = recordingUUID;
}
/**
* The constructor used when first creating a Recording.
*
......@@ -1220,7 +1230,7 @@ public class Recording extends FileModel {
this.speakersIds.add(speaker.getId());
}
private void setDeviceName(String deviceName) {
public void setDeviceName(String deviceName) {
if (deviceName == null) {
throw new IllegalArgumentException(
"The model name cannot be null");
......@@ -1426,7 +1436,7 @@ public class Recording extends FileModel {
}
return starFiles.length;
}
/**
* Gives the number of flags this recording has received.
*
......
package org.lp20.aikuma.model;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.lp20.aikuma.Aikuma;
......@@ -121,6 +123,7 @@ public class RecordingLig extends Recording {
this.speakerGender = spkrGndr;
}
/**
* Public constructor from super class Recording
* for existing recordings
......@@ -133,6 +136,7 @@ public class RecordingLig extends Recording {
r.respeakingId, r.sampleRate, r.durationMsec, r.format, r.fileType);
}
// Moves a WAV file with a temporary UUID from a no-sync directory to
// its rightful place in the connected world of Aikuma, with a proper name
// and where it will find it's best friend - a JSON metadata file.
......@@ -204,12 +208,7 @@ public class RecordingLig extends Recording {
File metadataFile = new File(getIndividualRecordingPath(),
this.name + METADATA_SUFFIX);
FileIO.writeJSONObject(metadataFile,encodedRecording);
Log.i(TAG, "Saved metadata file to " + metadataFile.getAbsolutePath());
// FileIO.writeJSONObject(new File(
// getRecordingsPath(), getGroupId() + "/" +
// id + METADATA_SUFFIX),
// encodedRecording);
Log.i(TAG, "Saved metadata file to " + metadataFile.getAbsolutePath());
}
/**
......@@ -224,14 +223,21 @@ public class RecordingLig extends Recording {
JSONObject jsonObj = FileIO.readJSONObject(metadataFile);
RecordingLig recording = new RecordingLig(read(jsonObj));
String code = (String) jsonObj.get(RecordingMetadataLig.metaRecordLang);
recording.recordLang = code.isEmpty() ? new Language(Aikuma.getLanguageCodeMap().get(code), code) : null;
recording.recordLang = code.isEmpty() ? null : new Language(Aikuma.getLanguageCodeMap().get(code), code);
JSONArray jsonArray = (JSONArray) jsonObj.get("languages");
recording.languages = Language.decodeJSONArray(jsonArray);
code = (String) jsonObj.get(RecordingMetadataLig.metaMotherTong);
recording.motherTong = code.isEmpty() ? new Language(Aikuma.getLanguageCodeMap().get(code), code) : null;