A followup to this question.
How can I clear the input buffer?
sleep(2);
// clear cin
getchar();
I only want the character that was typed in last, I want to discard any input that was put in while the program was asleep. Is there a way to do that?
Also, I don't want to wait actively to clear cin, thus I can't use ignore().
My approach would have been to get the current size of the buffer and if it's not equal to 0, silently empty the buffer. However, I have not found a way to get the size of the buffer. std::cin.rdbuf()->in_avail() always returns 0 for me. peek() also waits actively.
I don't want to use ncurses.
Having a system supporting tcgetattr/tcsetattr:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
class StdInput
{
// Constants
// =========
public:
enum {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(attributes);
}
// StdInput
// ========
public:
StdInput()
: m_restore(get())
{}
~StdInput()
{
set(m_restore, false);
}
void disable(unsigned flags) { disable_attributes(flags); }
void disable_blocking() { disable_attributes(Blocking); }
void restore() { set(m_restore); }
private:
static termios get() {
const int fd = fileno(stdin);
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("StdInput");
}
return attributes;
}
static void set(const termios& attributes, bool exception = true) {
const int fd = fileno(stdin);
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("StdInput");
}
}
static termios disable_attributes(unsigned flags) {
termios attributes = get();
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(a);
return attributes;
}
termios m_restore;
};
int main()
{
// Get something to ignore
std::cout << "Ignore: ";
std::cin.get();
// Do something
StdInput::clear();
std::cout << " Input: ";
std::string line;
std::getline(std::cin, line);
std::cout << "Output: " << line << std::endl;
return 0;
}
Related
I'm trying to convert a program (it's a bridge between vscode and a debug)
This program is written in C#.
It was based on the o vscode-mono-debug
(https://github.com/Microsoft/vscode-mono-debug/blob/master/src/Protocol.cs)
Well,
In C # I can read the standard input as a stream:
byte[] buffer = new byte[BUFFER_SIZE];
Stream inputStream = Console.OpenStandardInput();
_rawData = new ByteBuffer();
while (!_stopRequested) {
var read = await inputStream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0) {
// end of stream
break;
}
if (read > 0) {
_rawData.Append(buffer, read);
ProcessData();
}
}
I try this :
#define _WIN32_WINNT 0x05017
#define BUFFER_SIZE 4096
#include<iostream>
#include<thread>
#include <sstream>
using namespace std;
class ProtocolServer
{
private:
bool _stopRequested;
ostringstream _rawData;
public:
void Start()
{
char buffer[BUFFER_SIZE];
while (!cin.eof())
{
cin.getline(buffer,BUFFER_SIZE);
if (cin.fail())
{
//error
break;
}
else
{
_rawData << buffer;
}
}
}
};
int main()
{
ProtocolServer *server = new ProtocolServer();
server->Start();
return 0;
}
Input:
Content-Length: 261\r\n\r\n{\"command\":\"initialize\",\"arguments\":{\"clientID\":\"vscode\",\"adapterID\":\"advpl\",\"pathFormat\":\"path\",\"linesStartAt1\":true,\"columnsStartAt1\":true,\"supportsVariableType\":true,\"supportsVariablePaging\":true,\"supportsRunInTerminalRequest\":true},\"type\":\"request\",\"seq\":1}
This reads the first 2 lines correctly. Since the protocol does not put \n at the end, it gets stuck in cin.getline in the 3 interaction.
Switching to read() causes it to stay stopped at cin.read (), and does not read anything at all.
I found some similar questions:
StackOverFlow Question
And examples:
Posix_chat_client
But I do not need it to be necessarily asynchronous, but it works on windows and linux.
I'm sorry for my English
Thanks!
What you want is known as unformatted input operations.
Here's a 1:1 translation using just std::iostream. The only "trick" is using and honouring gcount():
std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {}; // or _rawData.clear(), e.g.
while (!_stopRequested) {
inputStream.read(buffer.data(), buffer.size());
auto read = inputStream.gcount();
if (read == 0) {
// end of stream
break;
}
if (read > 0) {
_rawData.append(buffer.begin(), buffer.begin() + read);
ProcessData();
}
}
I'd personally suggest dropping that read == 0 check in favour of the more accurate:
if (inputStream.eof()) { break; } // end of stream
if (!inputStream.good()) { break; } // failure
Note that !good() also catches eof(), so you can
if (!inputStream.good()) { break; } // failure or end of stream
Live Demo
Live On Coliru
#include <iostream>
#include <vector>
#include <atomic>
struct Foo {
void bar() {
std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {};
while (!_stopRequested) {
inputStream.read(buffer.data(), buffer.size());
auto read = inputStream.gcount();
if (read > 0) {
_rawData.append(buffer.begin(), buffer.begin() + read);
ProcessData();
}
if (!inputStream.good()) { break; } // failure or end of stream
}
}
protected:
void ProcessData() {
//std::cout << "got " << _rawData.size() << " bytes: \n-----\n" << _rawData << "\n-----\n";
std::cout << "got " << _rawData.size() << " bytes\n";
_rawData.clear();
}
static constexpr size_t BUFFER_SIZE = 128;
std::atomic_bool _stopRequested { false };
std::string _rawData;
};
int main() {
Foo foo;
foo.bar();
}
Prints (e.g. when reading its own source file):
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 92 bytes
I am working on a class that will read and write binary data to/from a file.
I am testing it by sending an 'a'. When I sent it to cout and it worked. I sent it to a text file, it sent î.
What is different about the ofstream that is causing this?
#include <iostream>
#include "bin2.h"
using namespace std;
int main()
{
bin myBin("e:\\Temp\\test.txt");
char data[1];
data[0] = 'a';
myBin.write(data, 1);
system("PAUSE");
return 0;
}
bin2.h
#pragma once
#include <fstream>
class bin
{
std::ofstream outfile;
std::ifstream infile;
std::filebuf *outBuff, *inBuff;
int buffSize = 5;
char* buffer;
//0 = input, 1 = output, 2 = ready to delete, 3 = unitialized
char mode = 3;
public:
//constructor with no parameters
bin(){ ; };
//if 'this' is constructed with a file, call init() to set object up
bin(char fileName[])
{
init(fileName);
};
void init(char fileName[])
{
try
{
//check if isUninitialized
if (!isUninitialized())
return;
//open the file and make sure it opened
outfile.open(fileName);
infile.open(fileName);
if (!outfile.is_open() || !infile.is_open())
throw std::runtime_error((std::string)"Failed to open file " + fileName);
//create buffer, get pointers to filebuffs, and set them to the new buffer
buffer = new char[buffSize];
outBuff = outfile.rdbuf();
outBuff->pubsetbuf(buffer, buffSize);
inBuff = infile.rdbuf();
inBuff->pubsetbuf(buffer, buffSize);
//set mode to input
mode = 0;
return
}
//if any exceptions were thrown, call the cleanup then rethrow the exception so
// the caller can handle the error as well
catch (std::exception & ex) {
cleanup();
throw ex;
}
};
virtual ~bin(){
cleanup();
};
//methods to check mode
bool modeIsInput(){ return mode == 0; };
bool modeIsOutput(){ return mode == 1; };
bool isReadyToDel(){ return mode == 2; };
bool isUninitialized(){ return mode == 3; };
std::string getMode(){
switch (mode) {
case 0: return "input";
case 1: return "output";
case 2: return "readyToDel";
case 3: return "unitialized";
default: return "invalid";
}
};
//method to write data into the object
bin * write(char data[], int length){
//make sure object is in input mode
if (mode != 0)
throw std::runtime_error("Cannot write to object when not in input mode. Current mode = " + getMode());
//DEBUG
std::cout << "Writing data: ";
std::cout.write(data, length);
std::cout << std::endl;
//end of DEBUG
//write data and return pointer to object
outfile.write(data, length);
return this;
};
private:
void cleanup()
{
delete buffer;
outfile.close();
infile.close();
//change mode to readyToDel
mode = 2;
};
};
You have:
bool modeIsInput(){ return mode = 0 ? true : false; };
bool modeIsOutput(){ return mode = 1 ? true : false; };
bool isReadyToDel(){ return mode = 2 ? true : false; };
bool isUninitialized(){ return mode = 3 ? true : false; };
I am sure you meant:
bool modeIsInput(){ return mode == 0 ? true : false; };
bool modeIsOutput(){ return mode == 1 ? true : false; };
bool isReadyToDel(){ return mode == 2 ? true : false; };
bool isUninitialized(){ return mode == 3 ? true : false; };
or better still.
bool modeIsInput(){ return mode == 0; };
bool modeIsOutput(){ return mode == 1; };
bool isReadyToDel(){ return mode == 2; };
bool isUninitialized(){ return mode == 3; };
I don't know whether fixing those will fix all your problems.
I copied my code as is and saved it it in a different file. The problem is solved, but I have no idea what caused it.
I'm trying to do a simple game (Pong) in C++. The game is a "Console-Game".
I've just write part of the code but now I found a trouble:
I create a _getch() and _kbhit() function
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
but when I press a key, that is printed on console. How I can prevent this?
My full code:
#include <iostream>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <stropts.h>
#include <sys/ioctl.h>
using namespace std;
void gotoxy(int x,int y){
printf("\x1b[%d;%df",y,x);
}
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
class Ball{
public:
};
class Game{
public:
void __init(){
this->pointL = 0;
this->pointR = 0;
}
void addScore(char side){
if(side == 'l') pointL++;
else if(side == 'r') pointR++;
else cout<< "ERROR-2";
return;
}
unsigned int getScore(char side){
if(side == 'l') return this->pointL;
else if (side == 'r') return this->pointR;
else return 0;
}
bool isPlaying(){
return this->playing;
}
bool stop(){
this->playing = false;
return true;
}
private:
unsigned int pointL, pointR;
bool playing;
};
class Player{
public:
int pos[5][2];
int maxX, maxY;
void __init(int maxX, int maxY, char side){
//create matrix with all cords of block of wall (r and l)
this->maxX = maxX;
this->maxY = maxY;
if(side == 'l')
for(int i = 0; i<5; i++){
pos[i][0] = 2;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else if(side == 'r')
for(int i = 0; i<5; i++){
pos[i][0] = maxX-4;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else
cout<<"ERRORE-1";
}
void moveUp(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == 0)?pos[i][1]:pos[i][1]-1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
void moveDown(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == this->maxY)?pos[i][1]:pos[i][1]+1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
};
int main(){
int a;
Game game;
Player pl1,pl2;
cout<< "Ridimensiona la finestra come meglio preferisci, quando hai fatto, premi un tasto per continuare";
_getch();
struct winsize size;
ioctl( 0, TIOCSWINSZ, (char *) &size );
printf("\e[2J\e[H");
pl1.__init(size.ws_row, size.ws_col, 'l');
pl2.__init(size.ws_row, size.ws_col, 'r');
//asap menu here
cout<< "TEST: " << size.ws_row;
char key;
while(game.isPlaying()){
if(_kbhit()){
key = _getch();
switch(key){ //when i press that keys, it's printed on terminal, how prevent?
case 'w':
pl1.moveUp();
break;
case 's':
pl2.moveDown();
break;
case 'q':
game.stop();
break;
}
}
}
return 0;
}
Here is a program which does not echo keystrokes but writes the characters to stderr instead. If you compile it, say, with g++ -o t t.cpp then you can start it with e.g. ./t 2>somefile, thus redirecting stderr to somefile.
In a second terminal you can do cat somefile after each keystroke in order to control what the program writes. (Warning: less somefile didn't work on my cygwin installation because the file growth appeared only in chunks in less (I told it to wait for input by pressing "F")).
Since all key strokes are forwarded to the controlling program Control-C or other means to send a signal to the running program via its controlling terminal doesn't work. You have to kill it from a different terminal.
The basic idea is that read() blocks in raw mode until input is available, so there is no need for a separate kbhit().
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
using namespace std;
int main()
{
struct termios oldt;
if( tcgetattr( 0, &oldt ) )
{
fprintf(stderr, "Error getting term attribs\n");
}
cfmakeraw(&oldt);
if( tcsetattr(0, TCSANOW, &oldt) )
{
fprintf(stderr, "Error setting term attribs\n");
}
char inp;
while(true)
{
int bytesRead = read(0, &inp, 1);
if( bytesRead <= 0)
{
fprintf(stderr, "oops, bytes read return val is %d\n", bytesRead);
}
else
{
write(2, &inp, 1);
}
}
}
You may use:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
// A class for mofdifying the behavour of a terminal.
class Terminal
{
// Types
// =====
public:
typedef speed_t speed_type;
// Terminal
// ========
public:
// Initialize the terminal file descriptor and store the attributes of the terminal.
Terminal(int fd)
: m_fd(fd), m_restore(get(fd))
{}
// Restore the orignal attributes of the terminal
~Terminal() {
set(m_fd, m_restore, false);
}
Terminal(const Terminal&) = delete;
const Terminal& operator = (const Terminal&) = delete;
int fd() const { return m_fd; }
void restore() { set(m_fd, m_restore); }
protected:
// Get attributes of a terminal
static termios get(const int fd) {
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("Terminal");
}
return attributes;
}
// Set attributes of a terminal
static void set(const int fd, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
// Set attributes of a terminal
static void set(const int fd, int action, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, action, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
private:
int m_fd;
termios m_restore;
};
// A class for mofdifying the input behavour of a terminal.
class StdInputTerminal : public Terminal
{
// Constants
// =========
public:
enum Attributes {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
// Clear available input in std::cin
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(fileno(stdin), attributes);
}
// StdInputTerminal
// ================
public:
// Initialize with 'stdin'
StdInputTerminal()
: Terminal(fileno(stdin))
{}
public:
// Disable attributes specified by any combination of Attributes flags
void disable(unsigned flags) { disable_attributes(flags); }
// Disable blocking
void disable_blocking() { disable_attributes(Blocking); }
protected:
// Set attributes of the terminal
static termios disable_attributes(unsigned flags) {
const int fd = fileno(stdin);
termios attributes = get(fd);
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(fd, a);
return attributes;
}
};
// Sample Usage
// ============
int kbhit() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
int result = 0;
char c;
if( ! std::cin.get(c))
std::cin.clear();
else
{
result = c;
std::cin.unget();
}
return result;
}
int getch() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
char result = 0;
while(true) {
std::cin.get(result);
if(std::cin.eof()) {
std::cin.clear();
usleep(100000);
}
else break;
}
if(std::cin.fail()) {
std::cin.clear();
result = 0;
}
return result;
}
// Test
// ====
int main()
{
std::cout << "Enter a single sample character: ";
char c;
std::cin.get(c);
std::cin.unget();
if(kbhit()) {
int ch = getch();
std::cout << "Entered character: " << char(ch);
if(kbhit()) {
int ch = getch();
std::cout << " Newline " << char(ch);
if(kbhit()) {
std::string line;
getline(std::cin, line);
std::cout << "\nToo many sample characters: " << line << '\n';
}
}
}
}
(Please excuse the incomplete classes, thy are experimental)
I have a 3rd party .dll (and relative .h and .lib) to control a device via USB.
I want to use the dll functions into a class (AOTF_controller) to implement my desired behaviour.
What I want to do is :
Connect to the device (connect() class function);
Initialize it (init() class function);
Set some parameters (setScanningFreq() class function)
Increase sequentially the frequency of my device (increaseFreq() class function)
Reset and close the USB connection.
I can obtain this behavior when I use the dll functions directly into the _tmain() therefore the device works correctly, but when I wrap the dll functions into a class and try to use the class something goes wrong.
I repeat the above process (list item 1-5) several times: sometimes it works fine, sometimes the program stop and the debugger gives me this error:
First-chance exception at 0x77533fb7 in AOTFcontrollerDebug.exe: 0xC0150014: The activation context activation stack for the running thread of execution is corrupt.
The error seems random, sometimes I can conclude 80 times the scan without any problem, sometimes it gives me error right at the first scan.
I tried to search for that error but I was not able to find anything useful.
Anyone can help? I guess could be related on how the dll functions are called in my class?
Here is the main function code:
// AOTFcontrollerDebug.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "AOTFcontrollerDebug.h"
#include "AOTF_Controller.h"
#include <iostream>
#include <string>
#include <sstream>
#include <AotfLibrary.h>
#define DEFAULT_STARTFREQUENCY 78
#define DEFAULT_ENDFREQUENCY 95.5
#define DEFAULT_NUMOFFRAMES 256
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
std::cout << "-----AOTF Controller Debugging-----"<<endl;
//input of scans to do
int repeatedScan;
std::cout << "Type how many repeated scan: "<<endl;
std::cin >> repeatedScan;
//instance
AOTF_Controller m_AOTF_Controller;
std::cout << "AOTF Controller instance done..."<<endl;
//loop over scans
for(int i =0;i<repeatedScan;i++)
{
m_AOTF_Controller.connect();
std::cout << "AOTF Controller connected..."<<endl;
std::cout << "Scan number : "<< (i + 1) <<endl;
m_AOTF_Controller.init();
//set the delta freq to increase at each step
m_AOTF_Controller.setScanningFreq(DEFAULT_STARTFREQUENCY, DEFAULT_ENDFREQUENCY, DEFAULT_NUMOFFRAMES);
//loop over wavelengths
int sleep_ms = 4;
for (int j =0; j <DEFAULT_NUMOFFRAMES; j++)
{
Sleep(sleep_ms) ;
m_AOTF_Controller.increaseFreq();
//std::cout << " "<< (j + 1) ;
}
// terminate scans
m_AOTF_Controller.reset();
m_AOTF_Controller.disconnect();
std::cout << endl <<"Scan number "<< (i + 1) << "terminated successfully" <<endl;
Sleep(sleep_ms*100) ;
}
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
and here the Aotf_Controller class code:
//Aotf_Controller.h
#pragma once
#include <AotfLibrary.h>
#include <string>
#include <sstream>
#include <iomanip>
#define CONVERSION_MHZ_TO_HZ 1000000
class AOTF_Controller
{
private:
enum Error {SUCCESSFUL , CONNECTION_ERROR, DISCONNECTION_ERROR, INIT_ERROR, RESET_ERROR , SET_ERROR }; // error enum values
HANDLE hAotfController;
int currentGain;
long currentFreq; // current frequency in Hz
long startFreq, endFreq, deltaFreq; // frequency values for the scanning in Hz
public:
AOTF_Controller(void);
~AOTF_Controller(void);
AOTF_Controller::Error connect();
AOTF_Controller::Error disconnect();
AOTF_Controller::Error init();
AOTF_Controller::Error setFreq(float freq); // for frequency value in MHZ (precision to the 3rd decimal i.e. KHz)
AOTF_Controller::Error setFreq(long freq); // for frequency value in Hz
AOTF_Controller::Error setGain(int gain);
AOTF_Controller::Error reset();
AOTF_Controller::Error setScanningFreq(float _startFreq, float _endFreq, int numOfFrames);
AOTF_Controller::Error increaseFreq();
};
//Aotf_Controller.cpp
#include "StdAfx.h"
#include "AOTF_Controller.h"
AOTF_Controller::AOTF_Controller(void)
{
currentGain = 0;
currentFreq = 0;
startFreq = 0;
endFreq = 0;
deltaFreq = 0;
hAotfController = NULL;
}
AOTF_Controller::~AOTF_Controller(void)
{
}
AOTF_Controller::Error AOTF_Controller::connect()
{
int iInstance = 0;
hAotfController = AotfOpen(iInstance);
if (!hAotfController)
{
return CONNECTION_ERROR;
}
else
{
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::disconnect()
{
if (!AotfClose (hAotfController))
{
return DISCONNECTION_ERROR;
}
else
{
hAotfController = NULL;
return SUCCESSFUL;
}
}
AOTF_Controller::Error AOTF_Controller::init()
{
std::string ampCom="dds a 0 16383\r"; //Command to set the amplitude parameter to the max
std::string modCom="mod dac * 16383\r";//Command to set the dac parameter to the max
int gain = 255; // set the gain to the max
if (!AotfWrite(hAotfController, ampCom.length(), (char *)ampCom.c_str()))
{
return Error::INIT_ERROR;
}
if (!AotfWrite(hAotfController, modCom.length(), (char *)modCom.c_str()))
{
return INIT_ERROR;
}
setGain(gain);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::reset()
{
std::string resetCom = "dds reset\r";
if(!AotfWrite(hAotfController, resetCom.length() , (char *)resetCom.c_str()))
{
return RESET_ERROR;
}
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(float freq)
{
long freqHz = (long)freq*CONVERSION_MHZ_TO_HZ;
setFreq(freqHz);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setFreq(long freq)
{
std::ostringstream oss; //stream to build the string
//building the string for the Frequency
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << freq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *) freqCom.c_str())) // set the frequency (80-120)
{
return SET_ERROR;
}
currentFreq = freq; // update monitoring variable in HZ
return Error::SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setGain(int gain)
{
std::ostringstream oss; //stream to build the string
//building the string for the Gain
oss << "dds gain -p* * " << gain << "\r";
std::string gainCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, gainCom.length(), (char * )gainCom.c_str())) // set the gain (0-255)
{
return SET_ERROR;
}
currentGain = gain;
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::setScanningFreq(float _startFreq, float _endFreq, int numOfFrames)
{
float FreqRange = (_endFreq - _startFreq); //calculate range
//calculate DeltaFrequency (frequency increase after each captured frame)
deltaFreq = (long) ((FreqRange/(float)(numOfFrames-1))*(float)CONVERSION_MHZ_TO_HZ); //conversion from MHz to Hz
startFreq = (long) (_startFreq*CONVERSION_MHZ_TO_HZ);
endFreq = (long) (_endFreq*CONVERSION_MHZ_TO_HZ);
setFreq(_startFreq);
return SUCCESSFUL;
}
AOTF_Controller::Error AOTF_Controller::increaseFreq()
{
if (deltaFreq ==0)
{
return SET_ERROR;
}
long newFreq = currentFreq + deltaFreq;
std::ostringstream oss;
oss << "dds f 0 !" << std::fixed << std::setprecision(0) << newFreq << "\r";
std::string freqCom = oss.str();
//send command to the AOTF
if(!AotfWrite(hAotfController, freqCom.length(), (char *)freqCom.c_str())) // set the frequency (80-120)value
{
return SET_ERROR;
}
currentFreq = newFreq;
return SUCCESSFUL;
}
I have to write a simple sinthesizer at university which uses sdl_mixer to generate sine waves. I got a code from my teacher which work on windows correctly, but in ubuntu it exits with segmentation fault.
I installed both sdl_mixer1.2-dev and sdl1.2-dev packages.
I tried a code that generates tone with sdl_audio. It worked fine, but I heard that for multi-channel playback, sdl_mixer is the solution.
The getch() part of the code is working well, the problem is with the sound manager part.
Can somebody help me to solve this problem?
Here is my code:
#include <iostream>
#include <termios.h>
#include <stdio.h>
#include<cmath>
#include <SDL/SDL_mixer.h>
#include<vector>
using namespace std;
class SoundManager
{
int channelnum;
vector<Mix_Chunk*> chunks;
public:
void init()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
}
SoundManager(int asked_channelnum=64)
{
channelnum = Mix_AllocateChannels(asked_channelnum);
chunks.assign(channelnum, (Mix_Chunk*)0);
}
int get_channelnum() const
{
return channelnum;
}
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }
Mix_Chunk * ownsample = new Mix_Chunk;
ownsample->alen = v.size()*2;
ownsample->abuf = (Uint8*)p;
ownsample->allocated = 1;
ownsample->volume = volume;
int playchannel = Mix_PlayChannel(-1, ownsample, 0);
if (playchannel != -1 && chunks[playchannel])
{
delete[] chunks[playchannel]->abuf;
Mix_FreeChunk(chunks[playchannel]);
}
if (playchannel != -1)
chunks[playchannel] = ownsample;
}
};
Mix_Chunk *ownsample = 0;
Mix_Chunk *samples = 0;
void hang()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
samples = Mix_LoadWAV("ding.wav");
ownsample = new Mix_Chunk;
ownsample->alen = s.size()*2;
ownsample->abuf =(unsigned char*) &(s[0]);
ownsample->allocated = 0;
ownsample->volume = 128;
cout << samples->alen << endl;
if (!samples)
{
cerr << "wav 'ding.wav' open error" << endl;
exit(1);
}
int channelnum = Mix_AllocateChannels(64);
if (channelnum != 64)
{
cerr << "warning: not as many channels are reserved as attended"<<endl;
}
if (Mix_PlayChannel(-1, ownsample, 0)==-1 )
{
cerr << "error on play" << endl;
}
// if (Mix_PlayChannel(-1, samples, 0)==-1 ) {
// cerr << "error on play" << endl;
// }
}
void pitty(SoundManager &sm)
{
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
sm.play_stereo(s);
}
static struct termios old, New;
/* Initialize New terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
New = old; /* make New settings same as old settings */
New.c_lflag &= ~ICANON; /* disable buffered i/o */
New.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &New); /* use these New terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void)
{
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
int ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
int getch(void)
{
return getch_(o);
}
/* Read 1 character with echo */
int getche(void)
{
return getch_(1);
}
int main(void)
{
SoundManager sm(16);
sm.init();
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
int c;
while (1)
{
c = getch();
cout <<"keycode:\n";
cout <<c;
sm.play_stereo(s);
}
return 0;
}
Thank you for your help in advance.
Greetings,
Istvan Velegi
(1) if you are getting a segmentation fault can you recompile the code with debugging symbols on (if you are using g++ or clang++); use -g3.
(2) run the program using a debugger and get a stack trace of where the code segmentation faults (use gdb).
This looks absolutely, totally bogus:
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
//...
ownsample->abuf = (Uint8*)p;
//...
delete[] chunks[playchannel]->abuf;
Yes, I realize chunks[playchannel] isn't ownsample yet, but you do put ownsample into the chunks queue, so eventually you will come back around and try to delete[] the internal array storage of a vector<short int>.
That's very bad.
This commented-out code actually seems to be the correct thing to have in place of const short int *p = &(v[0]):
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }