Skip to content
Snippets Groups Projects
Commit 68461955 authored by Aaron Cuevas Lopez's avatar Aaron Cuevas Lopez
Browse files

Extend FileReader functionality

parent 2b50044a
No related branches found
No related tags found
No related merge requests found
......@@ -25,23 +25,21 @@
#include "FileReaderEditor.h"
#include <stdio.h>
#include "KwikFileSource.h"
FileReader::FileReader()
: GenericProcessor("File Reader")
{
input = 0;
timestamp = 0;
enabledState(false);
counter = 0;
}
FileReader::~FileReader()
{
if (input)
fclose(input);
}
AudioProcessorEditor* FileReader::createEditor()
......@@ -54,7 +52,7 @@ AudioProcessorEditor* FileReader::createEditor()
bool FileReader::isReady()
{
if (input == 0)
if (input == nullptr)
{
sendActionMessage("No file selected in File Reader.");
return false;
......@@ -68,17 +66,26 @@ bool FileReader::isReady()
float FileReader::getDefaultSampleRate()
{
return 40000.0f;
if (input)
return currentSampleRate;
else
return 44100.0;
}
int FileReader::getDefaultNumOutputs()
{
return 16;
if (input)
return currentNumChannels;
else
return 16;
}
float FileReader::getBitVolts(int chan)
{
return 0.05f;
if (input)
return channelInfo[chan].bitVolts;
else
return 0.05f;
}
void FileReader::enabledState(bool t)
......@@ -89,42 +96,73 @@ void FileReader::enabledState(bool t)
}
void FileReader::setFile(String fullpath)
bool FileReader::setFile(String fullpath)
{
filePath = fullpath;
const char* path = filePath.getCharPointer();
if (input)
fclose(input);
input = fopen(path, "rb");
// Avoid a segfault if file isn't found
if (!input)
{
std::cout << "Can't find data file "
<< '"' << path << "\""
<< std::endl;
return;
}
fseek(input, 0, SEEK_END);
lengthOfInputFile = ftell(input);
rewind(input);
File file(fullpath);
String ext = file.getFileExtension();
if (!ext.compareIgnoreCase(".kwd"))
{
input = new KWIKFileSource();
}
else
{
sendActionMessage("File type not supported");
return false;
}
if (!input->OpenFile(file))
{
input = nullptr;
sendActionMessage("Invalid file");
return false;
}
if (input->getNumRecords() <= 0)
{
input = nullptr;
sendActionMessage("Empty file. Inoring open operation");
return false;
}
static_cast<FileReaderEditor*>(getEditor())->populateRecordings(input);
setActiveRecording(0);
}
void FileReader::setActiveRecording(int index)
{
input->setActiveRecord(index);
currentNumChannels = input->getActiveNumChannels();
currentNumSamples = input->getActiveNumSamples();
currentSampleRate = input->getActiveSampleRate();
startSample = 0;
stopSample = currentNumSamples;
currentSample = 0;
for (int i=0; i < currentNumChannels; i++)
{
channelInfo.add(input->getChannelInfo(i));
}
static_cast<FileReaderEditor*>(getEditor())->setTotalTime(samplesToMilliseconds(currentNumSamples));
readBuffer.malloc(currentNumChannels*BUFFER_SIZE);
}
String FileReader::getFile()
{
return filePath;
if (input)
return input->getFileName();
else
return String::empty;
}
void FileReader::updateSettings()
{
if (!input) return;
for (int i=0; i < currentNumChannels; i++)
{
channels[i]->bitVolts = channelInfo[i].bitVolts;
channels[i]->name = channelInfo[i].name;
}
}
......@@ -167,49 +205,33 @@ void FileReader::process(AudioSampleBuffer& buffer, MidiBuffer& events, int& nSa
int samplesNeeded = (int) float(buffer.getNumSamples()) * (getDefaultSampleRate()/44100.0f);
// if (counter == 0)
// {
// samplesNeeded = samplesNeeded - 2;
// counter = 1;
// } else {
// samplesNeeded = samplesNeeded + 2;
// counter = 0;
// }
if (ftell(input) >= lengthOfInputFile - samplesNeeded)
{
rewind(input);
}
size_t numRead = fread(readBuffer, 2, samplesNeeded*buffer.getNumChannels(), input);
int chan = 0;
int samp = 0;
for (size_t n = 0; n < numRead; n++)
{
if (chan == buffer.getNumChannels())
{
samp++;
timestamp++;
chan = 0;
}
int16 sample = readBuffer[n];
#ifdef JUCE_WINDOWS //-- big-endian format
// reverse the byte order
// float sample_f;
// AudioDataConverters::convertInt16BEToFloat(&readBuffer[n], &sample_f, 1);
#endif
*buffer.getWritePointer(chan++, samp) = -sample * getDefaultBitVolts();
}
int samplesReaded = 0;
while (samplesReaded < samplesNeeded)
{
int samplesToRead = samplesNeeded - samplesReaded;
if ((currentSample + samplesToRead) > stopSample)
{
samplesToRead = stopSample - currentSample;
if (samplesToRead > 0)
input->readData(readBuffer+samplesReaded,samplesToRead);
input->seekTo(startSample);
currentSample = startSample;
}
else
{
input->readData(readBuffer+samplesReaded,samplesToRead);
currentSample += samplesToRead;
}
samplesReaded += samplesToRead;
}
for (int i=0; i < currentNumChannels; i++)
{
input->processChannelData(readBuffer,buffer.getWritePointer(i,0),i,samplesNeeded);
}
timestamp += samplesNeeded;
static_cast<FileReaderEditor*>(getEditor())->setCurrentTime(samplesToMilliseconds(currentSample));
nSamples = samplesNeeded;
}
......@@ -217,10 +239,33 @@ void FileReader::process(AudioSampleBuffer& buffer, MidiBuffer& events, int& nSa
void FileReader::setParameter(int parameterIndex, float newValue)
{
switch (parameterIndex)
{
case 0: //Change selected recording
setActiveRecording(newValue);
break;
case 1: //set startTime
startSample = millisecondsToSamples(newValue);
currentSample = startSample;
static_cast<FileReaderEditor*>(getEditor())->setCurrentTime(samplesToMilliseconds(currentSample));
break;
case 2: //set stop time
stopSample = millisecondsToSamples(newValue);
currentSample = startSample;
static_cast<FileReaderEditor*>(getEditor())->setCurrentTime(samplesToMilliseconds(currentSample));
break;
}
}
unsigned int FileReader::samplesToMilliseconds(int64 samples)
{
return (unsigned int)(1000.f*float(samples)/currentSampleRate);
}
int64 FileReader::millisecondsToSamples(unsigned int ms)
{
return (int64)(currentSampleRate*float(ms)/1000.f);
}
void FileReader::saveCustomParametersToXml(XmlElement* parentElement)
{
......
......@@ -29,8 +29,9 @@
#include "../../../JuceLibraryCode/JuceHeader.h"
#include "../GenericProcessor/GenericProcessor.h"
#include "FileSource.h"
#define BUFFER_SIZE 102400
#define BUFFER_SIZE 1024
/**
......@@ -73,7 +74,7 @@ public:
int getDefaultNumOutputs();
float getBitVolts(int chan);
void setFile(String fullpath);
bool setFile(String fullpath);
String getFile();
void saveCustomParametersToXml(XmlElement* parentElement);
......@@ -83,16 +84,22 @@ private:
int64 timestamp;
int lengthOfInputFile;
FILE* input;
float currentSampleRate;
int currentNumChannels;
int64 currentNumSamples;
int64 startSample;
int64 stopSample;
Array<RecordedChannelInfo> channelInfo;
int16 readBuffer[BUFFER_SIZE];
int64 currentSample;
int bufferSize;
ScopedPointer<FileSource> input;
String filePath;
HeapBlock<int16> readBuffer;
int counter;
void setActiveRecording(int index);
unsigned int samplesToMilliseconds(int64 samples);
int64 millisecondsToSamples(unsigned int ms);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileReader);
......
......@@ -24,6 +24,7 @@
#include "FileReaderEditor.h"
#include "FileReader.h"
#include "../../UI/EditorViewport.h"
#include <stdio.h>
......@@ -36,15 +37,27 @@ FileReaderEditor::FileReaderEditor(GenericProcessor* parentNode, bool useDefault
lastFilePath = File::getCurrentWorkingDirectory();
fileButton = new UtilityButton("Select file",Font("Small Text", 13, Font::plain));
fileButton = new UtilityButton("F:",Font("Small Text", 13, Font::plain));
fileButton->addListener(this);
fileButton->setBounds(30,50,120,25);
fileButton->setBounds(5,27,20,20);
addAndMakeVisible(fileButton);
fileNameLabel = new Label("FileNameLabel", "No file selected.");
fileNameLabel->setBounds(20,80,140,25);
fileNameLabel->setBounds(30,25,140,20);
addAndMakeVisible(fileNameLabel);
recordSelector = new ComboBox("Recordings");
recordSelector->setBounds(30,50,120,20);
addAndMakeVisible(recordSelector);
currentTime = new DualTimeComponent(this, false);
currentTime->setBounds(5,80,175,20);
addAndMakeVisible(currentTime);
timeLimits = new DualTimeComponent(this,true);
timeLimits->setBounds(5,105,175,20);
addAndMakeVisible(timeLimits);
desiredWidth = 180;
setEnabledState(false);
......@@ -61,11 +74,17 @@ void FileReaderEditor::setFile(String file)
File fileToRead(file);
lastFilePath = fileToRead.getParentDirectory();
fileReader->setFile(fileToRead.getFullPathName());
fileNameLabel->setText(fileToRead.getFileName(), dontSendNotification);
setEnabledState(true);
if(fileReader->setFile(fileToRead.getFullPathName()))
{
fileNameLabel->setText(fileToRead.getFileName(), dontSendNotification);
setEnabledState(true);
}
else
{
clearEditor();
}
getEditorViewport()->makeEditorVisible(this, false, true);
repaint();
}
......@@ -98,6 +117,79 @@ void FileReaderEditor::buttonEvent(Button* button)
}
}
bool FileReaderEditor::setPlaybackStartTime(unsigned int ms)
{
if (ms > timeLimits->getTimeMilliseconds(1))
return false;
fileReader->setParameter(1,ms);
return true;
}
bool FileReaderEditor::setPlaybackStopTime(unsigned int ms)
{
if (ms > recTotalTime)
return false;
fileReader->setParameter(2,ms);
return true;
}
void FileReaderEditor::setTotalTime(unsigned int ms)
{
timeLimits->setTimeMilliseconds(0,0);
timeLimits->setTimeMilliseconds(1,ms);
currentTime->setTimeMilliseconds(0,0);
currentTime->setTimeMilliseconds(1,ms);
recTotalTime = ms;
}
void FileReaderEditor::setCurrentTime(unsigned int ms)
{
MessageManagerLock mml;
currentTime->setTimeMilliseconds(0,ms);
}
void FileReaderEditor::comboBoxChanged(ComboBox *combo)
{
fileReader->setParameter(0,combo->getSelectedId()-1);
getEditorViewport()->makeEditorVisible(this, false, true);
}
void FileReaderEditor::populateRecordings(FileSource* source)
{
recordSelector->clear(dontSendNotification);
for (int i=0; i < source->getNumRecords(); i++)
{
std::cout << "adding " << source->getRecordName(1) << std::endl;
recordSelector->addItem(source->getRecordName(i),i+1);
}
recordSelector->setSelectedId(1,dontSendNotification);
}
void FileReaderEditor::clearEditor()
{
fileNameLabel->setText("No file selected.",dontSendNotification);
recordSelector->clear(dontSendNotification);
timeLimits->setTimeMilliseconds(0,0);
timeLimits->setTimeMilliseconds(1,0);
currentTime->setTimeMilliseconds(0,0);
currentTime->setTimeMilliseconds(1,0);
setEnabledState(false);
}
void FileReaderEditor::startAcquisition()
{
recordSelector->setEnabled(false);
timeLimits->setEnable(false);
GenericEditor::startAcquisition();
}
void FileReaderEditor::stopAcquisition()
{
recordSelector->setEnabled(true);
timeLimits->setEnable(true);
GenericEditor::stopAcquisition();
}
void FileReaderEditor::saveEditorParameters(XmlElement* xml)
{
......@@ -120,4 +212,118 @@ void FileReaderEditor::loadEditorParameters(XmlElement* xml)
// }
// }
}
DualTimeComponent::DualTimeComponent(FileReaderEditor*e, bool isEditable)
: editor(e), editable(isEditable)
{
Label* l;
l = new Label("Time1");
l->setBounds(0,0,75,20);
l->setEditable(editable);
l->setFont(Font("Small Text",10,Font::plain));
if (editable)
{
l->addListener(this);
l->setColour(Label::ColourIds::backgroundColourId,Colours::lightgrey);
l->setColour(Label::ColourIds::outlineColourId,Colours::black);
}
addAndMakeVisible(l);
timeLabel[0] = l;
l = new Label("Time2");
l->setBounds(85,0,75,20);
l->setEditable(editable);
l->setFont(Font("Small Text",10,Font::plain));
if (editable)
{
l->addListener(this);
l->setColour(Label::ColourIds::backgroundColourId,Colours::lightgrey);
l->setColour(Label::ColourIds::outlineColourId,Colours::black);
}
addAndMakeVisible(l);
timeLabel[1] = l;
setTimeMilliseconds(0,0);
setTimeMilliseconds(1,0);
}
DualTimeComponent::~DualTimeComponent()
{
}
void DualTimeComponent::paint(Graphics &g)
{
String sep;
g.setFont(Font("Small Text",10,Font::plain));
g.setColour(Colours::darkgrey);
if (editable)
{
sep = "-";
}
else
{
sep = "/";
}
g.drawText(sep,78,0,5,20,Justification::centred,false);
}
void DualTimeComponent::setTimeMilliseconds(unsigned int index, unsigned int time)
{
int msFrac,secFrac,minFrac,hourFrac;
if (index > 1) return;
msTime[index]=time;
msFrac = time%1000;
time /= 1000;
secFrac = time%60;
time /= 60;
minFrac = time%60;
time /= 60;
hourFrac = time;
String text = String(hourFrac).paddedLeft('0',2) + ":" + String(minFrac).paddedLeft('0',2) + ":" +
String(secFrac).paddedLeft('0',2) + "." + String(msFrac).paddedLeft('0',3);
timeLabel[index]->setText(text,dontSendNotification);
}
unsigned int DualTimeComponent::getTimeMilliseconds(unsigned int index)
{
if (index > 1) return 0;
return msTime[index];
}
void DualTimeComponent::setEnable(bool enable)
{
timeLabel[0]->setEnabled(enable);
timeLabel[1]->setEnabled(enable);
}
void DualTimeComponent::labelTextChanged(Label* label)
{
StringArray elements;
unsigned int time;
bool res;
int index = (label == timeLabel[0]) ? 0 : 1;
elements.addTokens(label->getText(),":.",String::empty);
time = elements[0].getIntValue();
time = 60*time + elements[1].getIntValue();
time = 60*time + elements[2].getIntValue();
time = 1000*time + elements[3].getIntValue();
if (index == 0)
res = editor->setPlaybackStartTime(time);
else
res = editor->setPlaybackStopTime(time);
if (res)
{
setTimeMilliseconds(index,time);
}
else
{
setTimeMilliseconds(index,getTimeMilliseconds(index));
}
}
\ No newline at end of file
......@@ -29,7 +29,8 @@
#include "../Editors/GenericEditor.h"
class FileReader;
class DualTimeComponent;
class FileSource;
/**
......@@ -39,7 +40,8 @@ class FileReader;
*/
class FileReaderEditor : public GenericEditor
class FileReaderEditor : public GenericEditor,
public ComboBox::Listener
{
public:
......@@ -54,19 +56,56 @@ public:
void loadEditorParameters(XmlElement*);
bool setPlaybackStartTime(unsigned int ms);
bool setPlaybackStopTime(unsigned int ms);
void setTotalTime(unsigned int ms);
void setCurrentTime(unsigned int ms);
void comboBoxChanged(ComboBox *combo);
void populateRecordings(FileSource* source);
void startAcquisition();
void stopAcquisition();
private:
ScopedPointer<UtilityButton> fileButton;
ScopedPointer<Label> fileNameLabel;
ScopedPointer<ComboBox> recordSelector;
ScopedPointer<DualTimeComponent> currentTime;
ScopedPointer<DualTimeComponent> timeLimits;
FileReader* fileReader;
unsigned int recTotalTime;
File lastFilePath;
void clearEditor();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileReaderEditor);
};
class DualTimeComponent : public Component,
public Label::Listener
{
public:
DualTimeComponent(FileReaderEditor* e, bool isEditable);
~DualTimeComponent();
void setTimeMilliseconds(unsigned int index, unsigned int time);
unsigned int getTimeMilliseconds(unsigned int index);
void paint(Graphics& g);
void labelTextChanged(Label* label);
void setEnable(bool enable);
private:
ScopedPointer<Label> timeLabel[2];
unsigned int msTime[2];
FileReaderEditor* editor;
bool editable;
};
#endif // __FILEREADEREDITOR_H_D6EC8B48__
......@@ -38,7 +38,7 @@ int FileSource::getNumRecords()
String FileSource::getRecordName(int index)
{
return infoArray[activeRecord].name;
return infoArray[index].name;
}
int FileSource::getRecordNumChannels(int index)
......@@ -98,16 +98,23 @@ bool FileSource::fileIsOpened()
return fileOpened;
}
String FileSource::getFileName()
{
return filename;
}
bool FileSource::OpenFile(File file)
{
if (Open(file))
{
fileOpened = true;
fillRecordInfo();
filename = file.getFullPathName();
}
else
{
fileOpened = false;
filename = String::empty;
}
return fileOpened;
}
\ No newline at end of file
......@@ -57,9 +57,10 @@ public:
bool OpenFile(File file);
bool fileIsOpened();
String getFileName();
virtual int readData(int16* buffer, int nSamples) =0;
virtual void processChannelData(int16* inBuffer, float* outBuffer, int channel, int64 numSamples)=0;
virtual void seekTo(int64 sample) =0;
protected:
......@@ -75,6 +76,7 @@ protected:
bool fileOpened;
int numRecords;
int activeRecord;
String filename;
private:
virtual bool Open(File file)=0;
......
......@@ -215,4 +215,16 @@ int KWIKFileSource::readData(int16* buffer, int nSamples)
return 0;
}
return 0;
}
void KWIKFileSource::processChannelData(int16* inBuffer, float* outBuffer, int channel, int64 numSamples)
{
int n = getActiveNumChannels();
float bitVolts = getChannelInfo(channel).bitVolts;
for(int i=0; i < numSamples; i++)
{
*(outBuffer+i) = *(inBuffer+(n*i)+channel) * bitVolts;
}
}
\ No newline at end of file
......@@ -48,6 +48,8 @@ public:
void seekTo(int64 sample);
void processChannelData(int16* inBuffer, float* outBuffer, int channel, int64 numSamples);
private:
ScopedPointer<H5::H5File> sourceFile;
ScopedPointer<H5::DataSet> dataSet;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment