I'm very new to the AudioKit framework and I have been trying to understand a bit more about the DSP side to it. Whilst rummaging around in the source code I realised that AKNodeOutputPlot does not pull data from the node the same way others would.
In the DSP code for the AKAmplitudeTracker an RMS value is calculated for each channel and the result is briefly written to the output buffer but at the end of the for loop the node is essentially bypassed by setting the output to the original input:
void process(AUAudioFrameCount frameCount, AUAudioFrameCount bufferOffset) override {
for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
int frameOffset = int(frameIndex + bufferOffset);
for (int channel = 0; channel < channels; ++channel) {
float *in = (float *)inBufferListPtr->mBuffers[channel].mData + frameOffset;
float temp = *in;
float *out = (float *)outBufferListPtr->mBuffers[channel].mData + frameOffset;
if (channel == 0) {
if (started) {
sp_rms_compute(sp, leftRMS, in, out);
leftAmplitude = *out;
} else {
leftAmplitude = 0;
}
} else {
if (started) {
sp_rms_compute(sp, rightRMS, in, out);
rightAmplitude = *out;
} else {
rightAmplitude = 0;
}
}
*out = temp;
}
}
}
This makes sense since outputting the RMS value to the device speakers would sound terrible but when this node is used as the input to the AKNodeOutputPlot object RMS values are plotted.
I assumed that the leftAmplitude and rightAmplitude variables were being referenced somewhere but even if they are zeroed out the plot works just fine. I'm interested in doing some work on the signal without effecting the output so I'd love it someone could help me figure how the AKPlot is grabbing this data.
Cheers
AKNodeOutputPlot works with something called a "tap":
https://github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/User%20Interface/AKNodeOutputPlot.swift
There are also a few other taps that are not necessarily just for user interface purposes:
https://github.com/AudioKit/AudioKit/tree/master/AudioKit/Common/Taps
Taps allow you to inspect the data being pulled through another node without being inserted into the signal chain itself.
Related
I have 3 devices which send 8 bytes of data over CAN interface. To read the buffer from CAN I am using a while loop which looks something like this:
void CanServer::ReadFromCAN() {
data_from_buffer_.clear();
can_frame frame;
read_can_port_ = read(soc_, &frame, sizeof(struct can_frame));
if (read_can_port_ < 0) return;
id_ = frame.can_id&0x1FFFFFFF;
dlc_ = frame.can_dlc;
for (const auto& byte : frame.data)
data_from_buffer_.push_back(byte);
}
while (ros::ok()) {
std_msgs::Int32MultiArray tachometer_array;
std::vector<__u8> data_from_can;
/***
* Read for the Radar1
*/
this->ReadFromCAN();
if (read_can_port_ < 0) continue;
//ROS_INFO("Read from CAN");
if (id_ == can_id::RadarFrame1)
for (int i = 0; i < dlc_; i++) {
radar1_bytes_[i] = data_from_buffer_[i];
radar1_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar1_bytes_, 0)) {
frame_id = "radar1_link";
this->PulbishRadarPCL(frame_id, radar1_pub_, radar1_buffer_, 0);
radar1_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
if (id_ == can_id::RadarFrame2) {
for (int i = 0; i < dlc_; i++) {
radar2_bytes_[i] = data_from_buffer_[i];
radar2_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar2_bytes_, 1)) {
frame_id = "radar2_link";
this->PulbishRadarPCL(frame_id, radar2_pub_, radar2_buffer_, 1);
radar2_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
if (id_ == can_id::RadarFrame3) {
for (int i = 0; i < dlc_; i++) {
radar3_bytes_[i] = data_from_buffer_[i];
radar3_buffer_.push_back(data_from_buffer_[i]);
}
if (IsMagicWord(radar3_bytes_, 2)) {
frame_id = "radar3_link";
this->PulbishRadarPCL(frame_id, radar3_pub_, radar3_buffer_, 2);
radar3_buffer_.clear();
canFrame_.can_dlc = 0;
}
}
rate.sleep();
}
Where rate.sleep() is similar to sleep() function in C++.
Right now, I am running this while loop in 5 MHz however I think this is an overkill and I am getting almost 100% CPU usage on a 1 core.
I tried to play around with the delay time but I think this is highly inefficient and I wonder is there any other way to handle this?
It turns out that poll is what you need. Here is my example.
First, create a pollfd structure from <poll.h> header in Linux. I have decided to create a class member but you can create however you like:
pollfd poll_;
poll_.fd = soc_;
poll_.events = POLLIN;
poll_.revents = 0;
Here, soc_ is a socket and POLLIN means that you want to read from the socket.
Then, in my while loop, instead of delaying I just used this function at the beginning of my while loop:
poll_int = poll(&poll_, 1, 100);
if (poll_int <= 0) continue;
So poll() function returns value of 1 if the read was succesful and I made a timeout of 100ms (just a random number, I know that the data are coming at much higher rate)
With that, you will only read the data from socket whenever poll returns a value greater that 0.
Results? 3% CPU usage and if you want to add more data into your socket flow, poll will optimize for you so this is a scalable way of reading something like CAN bus.
I had a question regarding my code below. I'm reading a file containing lots of data of which some stuff is irrelevant. The data is written out on one line, so I cannot use nextLine or something.
For each vertex, I save the relevant information into dataperpoint. When I go to the next vertex, I want to clear the list to fill it with new relevant information.
The issue that I have is that each time I clear dataperpoint, all values in Map get cleared. When I then try to fill it, all previous positions in the Map get the same values.
How can I do this and make sure that each vertex will get his own list?
Looking forward to your suggestions!
public static Map<Integer, List<Double>> readData(File f) // throws IO exception?
{
// Create Map to store the vertex and list with relevant information in
List<Double> dataperpoint = new ArrayList<Double>();
Map<Integer, List<Double>> data = new HashMap<>();
// Open the scanner
try (Scanner in = new Scanner(f))
{
// To make sure the correct localization is used
in.useLocale(Locale.US);
// The first six integers contain irrelevant information
for (int step = 1; step <= 6; step++)
{
in.nextInt();
}
// Do the information for vertex 0 separately, since it has one data point less
int vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 2; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
while (in.hasNext()) // think of different statement later
{
dataperpoint = new ArrayList<Double>();
vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 3; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
}
in.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Use LinkedHashMap<> instead of HashMap<> it should solve your problem. Read this Difference between HashMap, LinkedHashMap and TreeMap
I am using this method in a Cocos2d X game.
void OpponentNode::discard(int cardNum)
{
log("\nOpponentNode::discard <%d>\n", cardNum);
for (int i = 0; i < vecOpponentHand.size(); i++)
{
if (vecOpponentHand.at(i) == cardNum)
{
vecOpponentHand.erase(vecOpponentHand.begin() + i);
break;
}
}
CardSprite * discardedCard;
for (int i = 0; i < vecOpponentCards.size(); i++)
{
if (vecOpponentCards.at(i)->getTag() == cardNum)
{
discardedCard = vecOpponentCards.at(i);
vecOpponentCards.erase(vecOpponentCards.begin() + i);
break;
}
}
log("\nOpponentNode::discard <%d>\n", cardNum);
discardedCard->makeFaceUp();
RotateTo * rotate = RotateTo::create(0.4 * SPEED_MULTIPLIER, 0);
MoveTo * move = MoveTo::create(0.4 * SPEED_MULTIPLIER,
origin + Vec2(visibleSize.width * 0.75, visibleSize.height * 0.6));
Spawn * spawn = Spawn::create(rotate, move, NULL);
CallFunc * callFunc = CallFunc::create(
[&]()
{
log("\nOpponentNode::discard <%d>\n", cardNum); //this one shows garbage/different value
if (delegate)
{
delegate->opponentNodeDidFinishDiscard(this, cardNum);
}
this->removeChild(discardedCard);
});
discardedCard->runAction(Sequence::create(spawn, callFunc, NULL));
log("\nOpponentNode::discard <%d>\n", cardNum);
}
Strangely, when I log the integer cardNum like above, I get different value from the log inside the lambda function. For example, I get "OpponentNode::discard <402>" from the top 2 logs and the bottom most log but get "OpponentNode::discard <64>" from the log inside the lambda function.
Other points:
The lambda block is executed last.
I mostly get values like 64 or garbage values like -15493456.
My guess is the integer cardNum is getting deallocated before the execution. Can anyone point me to the right direction?
You're capturing a reference to the cardNum parameter. I would think you want to capture that one by value.
It's not clear to me what delegate is. Assuming it's a class member then I think you just need [this, discardedCard, cardNum]. Which you could abbreviate to just [=], although I think the explicit one is clearer.
I am trying to make a little video player that has seek bar (with ffmpeg, of course). For that i need function that will, using data from frame and/or packet, get me current time in the video that should be set in seek slider.
It should work like this:
my_time = get_cur_time()
seek(my_time + 10)
assert(my_time+10 == get_cur_time())
seek(my_time - 10)
assert(my_time-10 == get_cur_time())
I do understand thatffmpeg does not support precise seeking, so equality here means "something reasonably cloae).
What code have i used for this thus far:
frame_time = frame->pts*av_q2d(video_dec_ctx->time_base) * 1000;
where frame is AVFrame and video_dec_ctx is AVCodecContext.
And for seeking:
int fn = ffmpeg::av_rescale(tsms,fmt_ctx->streams[video_stream->index]->time_base.den,
fmt_ctx->streams[video_stream->index]->time_base.num);
int frame = fn/1000;
printf("\t avformat_seek_file to %d\n",frame);
int flags = AVSEEK_FLAG_FRAME;
if (frame < this->frame->pts)
flags |= AVSEEK_FLAG_BACKWARD;
if(ffmpeg::av_seek_frame(fmt_ctx,video_stream->index,frame,flags))
{
printf("\nFailed to seek for time %d",frame);
return false;
}
avcodec_flush_buffers(video_dec_ctx);
int got_frame = 0;
do
if (av_read_frame(fmt_ctx, &pkt) >= 0) {
decode_packet_ro(&got_frame, 0);
av_free_packet(&pkt);
}
else
{
read_cache = true;
pkt.data = NULL;
pkt.size = 0;
break;
}
while(!(got_frame && this->frame->pts >= frame));
The code does forward seeking passably, but after any attempt of backward seeking my second assertion fails. After seeking to previous position, my method of getting time does not return position less that one before seeking. That causes my seek slider to work grossly incorrectly.
I have a QVector in which I'm constantly appending data so I can plot on a QwtPlot. But with a high frequency I guess the vector becames too large and the program crashes.
My question is, how can I create a QwtCurve which is only beggining in some point of time, bacause the time that has already passed is not necessary in the vector as it was already plotted.
here's my code:
QVector<double> xv;
QVector<double> cv1;
QVector<double> cv2;
as global variables,
void gui::process_new_info(QByteArray array)
{
int v = 0;
double f = ui->frequency->value();
xv.append(sizeof_array/f);
char *buf = array.data();
if (ui->ecgPlux->isChecked() == true || ui->channel_1->currentIndex() != 0)
{
cv1.append(buf[1]);
QwtPlotCurve *curve1 = new QwtPlotCurve;
curve1->attach(plot_all[0]);
curve1->setData(xv,cv1);
curve1->setPen(QPen(Qt::blue,1));
plot_all[0]->replot();
QwtPlotCurve *curve2 = new QwtPlotCurve;
curve2->attach(plot[0]);
curve2->setData(xv,cv1);
curve2->setPen(QPen(Qt::blue,1));
plot[0]->replot();
}
if (ui->xyzPlux->isChecked() == true || ui->channel_2->currentIndex() != 0)
{
cv2.append(buf[2]);
QwtPlotCurve *curve3 = new QwtPlotCurve;
curve3->attach(plot_all[1]);
curve3->setData(xv,cv2);
curve3->setPen(QPen(Qt::blue,1));
plot_all[0]->replot();
QwtPlotCurve *curve4 = new QwtPlotCurve;
curve4->attach(plot[1]);
curve4->setData(xv,cv1);
curve4->setPen(QPen(Qt::blue,1));
plot[1]->replot();
}
//printf ("%d ->", buf[0]);
fprintf (data, "%d,", buf[0]);
for (int i = 1; i < 9; i++)
{
v = buf[i];
//printf ("%d,", v);
fprintf (data, "%d,", v);
}
//printf ("\n");
fprintf (data, "\n");
sizeof_array++;
}
QwtPlotCurve
http://qwt.sourceforge.net/class_qwt_plot_curve.html
inherits from QwtPlotSeriesItem
http://qwt.sourceforge.net/class_qwt_plot_series_item.html
There is a warning in setData
The item takes ownership of the data object, deleting it when its not used anymore.
It probably isn't the fact that you are growing too big... it may be that you are accessing something that Qwt deleted.
Run it in a debugger, and look at the stack trace for where it died, or put in a bunch of qDebug() lines to see where it is dying.
If it is something with the data being too large, you could pop off items off of the head of your vector, before setting the vector.
Hope that helps.