Programming links:
20071228
OpenSuSE 10.2: Πρόβλημα με Ελληνικά και τόνους;; Αφαίρεσε το SCIM.
20071227
OpenSuSE 10.2: Winodws Media support plug in firefox.
20071204
OpenSuSE 10.2: mounting for write NTFS partiotion.
Για να μπορούμε να γράψουμε σε NTFS partiotion στο Open SuSE χρησιμοποιούμε τα πακέτα fuse, ntfs-3g από το http://download.opensuse.org/repositories/filesystems/openSUSE_10.2/
(όχι το ntfsprogs-fuse από το package repositories του yast!).
"the ntfs-fuse uses ntfsmount and is vastly inferior compared to ntfs-3g; there is a creation limit of 10 files per directory. If you want to use a ntfs partitions for more serious work, you should consider using a more appropriate ntfs driver such as ntfs-3g."
Απο το link που δίνεται παρακάτω.Κατόπιν ρυθμίζουμε το /etc/fstab:
#Device Mountpoint Filesystem ParametersLink: http://en.opensuse.org/NTFS
/dev/sda1 /windows/C ntfs-3g user,users,gid=users,umask=0002 0 0
Unix: tar archiving / multi-volume archives / gzipped.
Έστω ότι θέλουμε να αποθηκεύσουμε σε ένα αρχείο tar όλα τα αρχεία που βρίσκονται στο /home/ggia μαζί με τα subdirs, files etc. Τρέχουμε:
tar cvf ggia_backup.tar /home/ggia
Παράμετροι που χρησιμοποιήσαμε είναι:
c - create (δημιουργία αρχείου tar)
v - verbose (να μας δείχνει ποια αρχεία επεξεργάζεται στην οθόνη)
f - filename (το όνομα του αρχείου tar που θα δημιουργήσουμε)
Αυτή η εντολή θα αποθηκεύση ΟΛΟΚΛΗΡΟ το path + subdirs.. Μπορούμε επίσης να προσθέσουμε το -p για να διατηρηθούν τα file permissions:
tar cpvf ggia_backup.tar /home/ggia
p - keep file permissions in tar
Μεταφέρουμε το αρχείο ydol_backup.tar σε ένα άλλο dir, π.χ. στο /tmp/ Με την εντολή
tar xf ggia_backup.tar
Σου ξαναβγάζει το directory με όλα τα αρχεία και subdirectories που έχεις βάλει μέσα στο tar (σχετικά όπως έδωσες στην αρχή.. πχ.. το /home/ggia θα δώσεις /tmp/home/ggia/..).
Αν θέλουμε μπορούμε το αρχείο να το συμπιέσουμε με το gzip ggia_backup.tar / αποσυμπιέζεται με το gunzip ggia_backup.tar.gz.
Αν θέλουμε το αρχείο να χωρέσει μέσα σε cd/dvd μπορούμε να δώσουμε εντολή στο tar να το χωρίσει σε ξεχωριστά αρχεία.
tar cvf ggia_backup.tar -L1000000 /home/ggia
L - ή αλλιώς --tape-length=<nr> (nr * 1024).
Για παράδειγμα το 1000000 * 1024 = 1 Gbyte περίππου.
Βέβαια ο παραπάνω τρόπος θέλει χειροκίνητα να δώσεις το όνομα του επόμενου αρχείου tar το οποίο γίνεται με την εντολή n ggia_backup1.tar κλπ κλπ.
Link: Archives Longer than One Tape or Disk
Στο παραπάνω link υπάρχει και script που μπορεί να περαστεί με την παράμετρο -F στο tar ώστε αυτόματα το tar να δημιουργήσει splitted tar archives.. αλλά δεν κατάφερα να το δουλέψω.
20071127
Newline terminator in Unix/Linux, Windows and Mac (+convertion methods).
Windows Newline: Carriage Return char(13) ή 0Dh + Line Feed char(10) ή 0Ah.
Unix Newline: Line Feed char(10) ή 0Ah.
Mac OS X Newline: Line Feed char(10) ή 0Ah.
Mac OS up to ver9: Carriage Return char(13) ή 0Dh.
Σε unix ή Windows με cygwin με χρήση sed/perl μπορούμε να μετατρέψουμε txt αρχείο:
sed -e 's/$/\r/' inputfile > outputfile # UNIX to DOS (adding CRs)
sed -e 's/\r$//' inputfile > outputfile # DOS to UNIX (removing CRs)
perl -p -e 's/(\r\n|\n|\r)/\r\n/g' inputfile > outputfile # Convert to DOS
perl -p -e 's/(\r\n|\n|\r)/\n/g' inputfile > outputfile # Convert to UNIX
perl -p -e 's/(\r\n|\n|\r)/\r/g' inputfile > outputfile # Convert to old Mac
Link: en.wikipedia article about Newline.
20071126
Convert a tab delimited file to CSV format using Regular Expressions in vi substitution.
a) At the end of each line delete all the whitespaces (one or more):
:1,$s/\s\+$//g
b) Substitute all the whitespaces (one or more) with comma ',' :
:1,$s/\s\+/,/g
Remove all "^M" characters from a file using vi.
:%s/^M//g
The "^M" in the above line has to be typed in by pressing CTRL+v and then CTRL+M.
Also by
:%s/\r\(\n\)/\1/g from here.
Convert all new lines to tab delimited using regex in vi.
For example file f.txt:
a1
a2
a3
..
will be converted to:
a1 a2 a3 ..
Post about Regular Expressions.
20071123
Regular expressions links/briefly.
Perl Regular Expression Quick Reference 1.05.
Perl Regular Expression Tutorial.
C++ Boost.Regex library for Perl Regular Expression Syntax.
Perl Regular Expressions briefly:
\ Quote the next metacharacter
^ Match the beginning of the line
. Match any character (except newline)
$ Match the end of the line (or before newline at the end)
| Alternation
() Grouping
[] Character class
* Match 0 or more times
+ Match 1 or more times
? Match 1 or 0 times
{n} Match exactly n times
{n,} Match at least n times
{n,m} Match at least n but not more than m times
* Match 0 or more times
+ Match 1 or more times
? Match 1 or 0 times
{n} Match exactly n times
{n,} Match at least n times
{n,m} Match at least n but not more than m times
*? Match 0 or more times
+? Match 1 or more times
?? Match 0 or 1 time
{n}? Match exactly n times
{n,}? Match at least n times
{n,m}? Match at least n but not more than m times
\t tab (HT, TAB)
\n newline (LF, NL)
\r return (CR)
\f form feed (FF)
\a alarm (bell) (BEL)
\e escape (think troff) (ESC)
\033 octal char (think of a PDP-11)
\x1B hex char
\c[ control char
\l lowercase next char (think vi)
\u uppercase next char (think vi)
\L lowercase till \E (think vi)
\U uppercase till \E (think vi)
\E end case modification (think vi)
\Q quote (disable) pattern metacharacters till \E
\w Match a "word" character (alphanumeric plus "_")
\W Match a non-word character
\s Match a whitespace character
\S Match a non-whitespace character
\d Match a digit character
\D Match a non-digit character
\b Match a word boundary
\B Match a non-(word boundary)
\A Match only at beginning of string
\Z Match only at end of string, or before newline at the end
\z Match only at end of string
\G Match only where previous m//g left off (works only with /g)
Decoding Regular Expressions
| Symbol | What It Means | Example | What It Might Find |
|---|---|---|---|
| + | find 1 or more of preceding item | ta+ | ta, taa, taaa |
| * | find 0 or more of preceding item | ba* | b, ba, baa, baaa |
| ? | preceding item is optional | ab?c | abc, ac |
| . | match any character (except return) | 1.2 | 1 2, 122, 1d2, 1$2 |
| [^x] | match any character except x | us[^a] | usb, usc, usd, use |
| [0-9] | match any digit | 9021[0-9] | 90210 through 90219 |
| ^ | match start of line | ^hello | matches hello only at beginning of line |
| $ | match end of line | end$ | matches end only at end of line |
| ( ) | group items together | (ab)+ | ab, abab, ababab |
20071120
C++: Defining/initializing static member(s) within a class.
// file: obj.hΣτον παραπάνω κώδικα βλέπουμε ένα παράδειγμα χρήσης στατικών μεταβλητών σε C++ class. Οι μεταβλητές nr, και initialized είναι ίδιες σε όλες τα στιγμιότυπα (instances) αντικειμένων από το class obj. Μάλιστα η μεταβλητή έχει αρχική μεταβλητή false, η οποία δεν ορίζεται μέσα στον ctor αλλά εξωτερικά.
class obj {
public:
obj(void) { }; // ctor
~obj(void) { }; // dtor
private:
static int nr;
static bool initialized;
}
// file: obj.cpp
#include "obj.h"
// Waring: Static members need external definition!
int obj::nr;
// default value of static member:
bool obj::initialized=false;
20071116
C++: Example of class with ctor, increment operator (prefix and suffix) and ostream overloading.
// simple Int class with ctor, increment operator and ostream overloadLink: Περισσότερα για την διαφορά prefix/suffix.
class Int{
public:
Int& operator++();
const Int operator++( int n );
Int(int i): _i(i) { };
friend ostream& operator <<(ostream& os, const Int &i);
private:
int _i;
};
// look difference between return values: Int& (in prefix)
Int& Int::operator++() {
_i++; // Handle case where no argument is passed.
return *this;
}
// and const Int (in postfix)
const Int Int::operator++( int n ) {
Int tmp(*this);
if( n != 0 )
for (int nr=0; nr<n; ++nr, ++(*this));
else
++(*this);
return tmp;
}
// overloading << operator for Int class
ostream& operator <<(ostream& os, const Int &i) {
os << i._i;
return os;
}
void main() {
Int gg(0);
cout << gg.operator++(25) << endl ; // Increment by 25 but shown 0
cout << gg << endl; // in next reference is shown as 25
// gg = 25
cout << gg++ << endl; // gg is 25. Only in the next reference will it be 26
cout << gg << endl; // gg is 26.
// gg = 26
cout << ++gg << endl; // ggia is immidiately 27
cout << gg << endl; // ggia is 27
return;
}
C++: difference between prefix and suffix increment / decrement.
- As a prefix : i.e. when the operator precedes the variable (as in ++ i, where i is the integer variable)
If we write:
i1 = 10;
i2 = ++ i1;
This is the same as:
i1 = 10;
i1 = i1 + 1;
i2 = i1;
At the end of these steps the value of both i1 and i2 will be 11. When used as a prefix, the variable is first incremented and later assigned.
- As a suffix: i.e. when the variable precedes the operator (as in i ++).
If we write:
i1 = 10;
i2 = i1 ++ ;
This is the same as writing:
i1 = 10;
i2 = i1;
i1 = i1 + 1;
At the end of these steps the value of i2 will be 10 and that of i1 will be 11. When used as a postfix, the variable value is first assigned and later incremented.
// suffix
int sum=5; // sum is 5
cout << sum++; // sum is 5. Only in the next reference to sum will it be 6
cout << " " << sum << endl; // sum is now 6
// prefix
sum=5; // sum is 5
cout<<++sum; // sum is immediately 6
cout<<" "<<sum; // sum is 6
Remember: When used as a prefix ( ++i ) compiler will first increment and then assign. When used as a suffix, assignment is done first and then incrementing is performed.
Link: C++ Operators - IV.20071109
Visual Studio .NET 2005: Static library creation/usage.
//---------------------------------------------------//
Walkthrough: Creating and Using a Static Library
In this walkthrough, you will create a static library (LIB) containing useful routines that can be used by other applications. Using static libraries is a great way to reuse code. Rather than re-implementing these routines in every program you create, you write them once and reference them from applications that need the functionality.
This walkthrough uses native C++. For a walkthrough using native C++ to create a dynamic link library (DLL), see Walkthrough: Creating and Using a Dynamic Link Library. For a walkthrough using Visual C++ that targets the Common Language Runtime, see Walkthrough: Creating and Using a Managed Assembly.
This walkthrough covers the following:
-
Creating a new static library project
-
Adding a class to the static library
-
Creating an application that references the static library
-
Using the functionality from the static library in the console application
-
Running the application
This topic assumes you understand the fundamentals of the C++ language.
To create a new static library project
-
From the Project types pane, under Visual C++, select Win32.
To add a class to the static library
-
// MathFuncsLib.h
namespace MathFuncs
{
class MyMathFuncs
{
public:
// Returns a + b
static double Add(double a, double b);
// Returns a - b
static double Subtract(double a, double b);
// Returns a * b
static double Multiply(double a, double b);
// Returns a / b
// Throws DivideByZeroException if b is 0
static double Divide(double a, double b);
};
} // MathFuncsLib.cpp
// compile with: /c /EHsc
// post-build command: lib MathFuncsLib.obj
#include "MathFuncsLib.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b;
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b;
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b;
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw new invalid_argument("b cannot be zero!");
}
return a / b;
}
}
NoteIf building from the command line, you must build the program in two steps. First, compile the code using Cl.exe with the /c compiler option (cl /c /EHsc MathFuncsLib.cpp). This will create an object file named MathFuncsLib.obj. For more information, see /c (Compile Without Linking). Second, link the code using the Library Manager Lib.exe (lib MathFuncsLib.obj). This will create the static library MathFuncsLib.lib. For more information on the Library Manager, see LIB Reference.
To create an application that references the static library
To use the functionality from the static library in the console application
To use the math routines that were created in the static library, you must reference it. To do this, select References… from the Project menu. From the Property Pages dialog, expand the Common Properties node and select References. Then select the Add New Reference… button. For more information on the References… dialog, see References, Common Properties, <Projectname> Property Pages Dialog Box.
The Add Reference dialog is displayed. This dialog lists all the libraries that you can reference. The Project tab lists all the projects in the current solution and any libraries they contain. From the Projects tab, select MathFuncsLib. Then select OK. For more information on the Add Reference dialog, see Add Reference Dialog Box.
To reference the header files of the static library, you must modify the include directories path. To do this, from the Property Pages dialog, expand the Configuration Properties node, then the C/C++ node, and select General. Next to Additional Include Directories, type in the path to the location of the MathFuncsLib.h header file.
You can now use the MyMathFuncs class in this application. Replace the contents of MyExecRefsLib.cpp with the following code:
// MyExecRefsLib.cpp
// compile with: /EHsc /link MathFuncsLib.lib
#include <iostream>
#include "MathFuncsLib.h"
using namespace std;
int main()
{
double a = 7.4;
int b = 99;
cout << "a + b = " <<
MathFuncs::MyMathFuncs::Add(a, b) << endl;
cout << "a - b = " <<
MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
cout << "a * b = " <<
MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
cout << "a / b = " <<
MathFuncs::MyMathFuncs::Divide(a, b) << endl;
return 0;
}Build the executable by selecting Build Solution from the Build menu.
To run the application
Make sure MyExecRefsLib is selected as the default project. From the Solution Explorer, select MyExecRefsLib, and then select Set As StartUp Project from the Project menu.
To run the project, select Start Without Debugging from the Debug menu. The output should look like this:
a + b = 106.4
a - b = -91.6
a * b = 732.6
a / b = 0.0747475
Release έκδοση:
Debug έκδοση:
20071102
C++ Boost: Reading all the text files of directory and apply a substitution using a regular expression.
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/regex.hpp>
using namespace boost::filesystem;
using namespace std;
// Apply Regular Expression + substitution
string process_str(string str, string regex, string substitution) {
cout << "applying regular expression.. " << regex << endl;
string result=string();
boost::regex reg(regex);
result=boost::regex_replace(str,reg,substitution);
return result;
}
// Read file fname and return its contents in string format
string load_data_in_str(string fname) {
// ifstream fIn;
// Error 1 error C2872: 'ifstream' : ambiguous symbol
// Because ifstream is defined by 2 namespaces:
// namespace std and boost::filesystem (!)
// Use either std::ifstream fIn; either boost::filesystem::ifstream fIn;
// If I use boost::filesystem::ifstream
boost::filesystem::ifstream fIn;
// Obj fIn can has as argument string fname:
// fIn.open(fname,std::ios::in);
// either obj boost::filesystem::path:
// fIn.open(path(fname),std::ios::in);
// But for comparibility with std::ifstream I use:
fIn.open(fname.c_str(),std::ios::in);
if (!fIn) {
cerr << "string load_data_in_str(string fname)" << endl;
cerr << "Error reading the file: " << fname << endl;
getchar();
exit(0);
}
string l;
stringstream ss;
ss << fIn.rdbuf();
return ss.str();
}
// Write to filename fname contents of string data (with default the overwrite: append=false)
void write_str_in_file(string fname, string data, bool append=false) {
// For the same reason as in function string load_data_in_str(string fname)
// I choose with lib I will use from namespaces: (boost::filesystem:: vs std::).
boost::filesystem::ofstream fOut;
if (append)
fOut.open(fname.c_str(),ios::app);
else
fOut.open(fname.c_str(),ios::out);
if (!fOut) {
cerr << "void write_str_in_file(string fname, string data, bool append)" << endl;
cerr << "Error writing to file: " << fname << endl;
getchar();
exit(0);
}
fOut << data;
fOut.close();
}
int main(int argc, char* argv[]) {
if (argc!=5) {
cerr << "Usage: " << argv[0]
<< " [ files dir ] [ reg ex ] [ substritution ] [ out file dir ]" << endl;
cerr << "Press <enter> to continue.." << endl;
getchar();
return (EXIT_FAILURE);
}
// template <class Path> Path system_complete(const Path& p);
// Effects: Composes a complete path from p, using the same rules
// used by the operating system to resolve a path passed as the
// filename argument to standard library open functions.
// Returns: The composed path.
// Postcondition: For the returned path, rp, rp.is_complete() is true.
// Throws: If p.empty().
// Returns: The composed path.
// [Note: For POSIX, system_complete(p) has the same semantics as complete(p, current_path()).
// For Windows, system_complete(p) has the same semantics as complete(ph, current_path())
// if p.is_complete() || !p.has_root_name() or p and base have the same root_name().
// Otherwise it acts like complete(p, kinky), where kinky is the current directory for
// the p.root_name() drive. This will be the current directory of that drive the last
// time it was set, and thus may be residue left over from a prior program run by the
// command processor! Although these semantics are often useful, they are also very error-prone.
path InputPath=system_complete(path(argv[1],native));
// in #include <stdlib.h> are defined EXIT_FAILURE and EXIT_SUCCESS
if (!exists(InputPath)) {
cerr << "Error: the directoty " << InputPath
<< " does not exist." << endl;
return (EXIT_FAILURE);
}
if (!is_directory(InputPath)) {
cout << InputPath << " is not a directory!" << endl;
return (EXIT_SUCCESS);
}
path OutputPath=system_complete(path(argv[4],native));
if (!exists(OutputPath)) {
cerr << "Error: the directoty " << OutputPath
<< " does not exist." << endl;
return (EXIT_FAILURE);
}
if (!is_directory(OutputPath)) {
cout << InputPath << " is not a directory!" << endl;
return (EXIT_SUCCESS);
}
directory_iterator end;
for (directory_iterator it(InputPath); it!= end; ++it) {
cout << it->leaf() << endl;
cout << it->string();
string load_txt;
if (is_directory(*it))
cout << " (dir)";
else {
// Read file into the string load_txt
load_txt=load_data_in_str(it->string());
// Substitute the match of regular expression argv[2]
// with the text of substitution argv[3].
load_txt=process_str(load_txt, argv[2], argv[3]);
/// write_str_in_file(OutputPath.directory_string()+(it->leaf()),load_txt);
// basic_path& operator/=(const basic_path& rhs);
// Effects: The path stored in rhs is appended to the stored path.
// The following function as we read from documenation @ www.boost.org
// http://www.boost.org/libs/filesystem/doc/tr2_proposal.html#basic_path-observers
// path(OutputPath)/=path(it->leaf())
// Gets OutputPath = OutputPath + / + path(it->leaf());
// It concatenates path + filename.
// At the end with .string() we convert to string in order to pass it as argument
write_str_in_file((path(OutputPath)/=path(it->leaf())).string(),load_txt);
}
cout << endl;
}
getchar();
return (EXIT_SUCCESS);
}
20071029
C++: STL vector<>::front/begin() and vector<>::back/end() methods.
// vector::front - Returns reference to first element of vector.
// vector::back - Returns reference to last element of vector.
// vector::push_back - Appends (inserts) an element to the end of a
// vector, allocating memory for it if necessary.
// vector::size - Returns number of elements in the vector.
// vector::begin - Returns an iterator to start traversal of the vector.
// vector::end - Returns an iterator for the last element of the vector.
// vector::erase - Deletes elements from a vector (single & range).
vector<int> vec;
// Intialize the array to contain the members [100, 200, 300, 400]
for (int i=0; i<4; i++)
vec.push_back((i + 1) * 100);
cout << "First element: " << vec.front() << endl;
cout << "Last element: " << vec.back() << endl;
cout << "Elements in vector: " << vec.size() << endl;
// Delete the last element of the vector. Remember that the vector
// is 0-based, so theVector.end() actually points 1 element beyond the end.
vec.erase(vec.end() - 1);
cout << endl << "After erasing last element, new last element is: " << vec.back() << endl;
// Delete the first element of the vector.
vec.erase(vec.begin());
cout << "After erasing first element, new first element is: "
<< vec.front() << endl;
cout << "Elements in vector: " << vec.size() << endl;
// Insert an element (number -11) in front of the vector.
vec.insert(vec.begin(),-11);link: Visual C++ Developer Center / vector::front and vector::back
C++ Classes: Overloading ostream/istream operators, defining copy ctor, assignment operator, and operator +.
/*-------------------------------------------------------*/file obj_test.h:/*-------------------------------------------------------*/#ifndef __OBJ_TEST_H
#define __OBJ_TEST_H
#include <vector>
#include <string>
using namespace std;
class obj_test {
public:
obj_test(void);
obj_test(vector<float> samples): _samples(samples) { };
~obj_test(void);
// copy constructor
obj_test(const obj_test& obj);
// assignment operator
obj_test& operator =(const obj_test& rhs);
// + operator
obj_test operator +(const obj_test& rhs);
friend ostream& operator <<(ostream& os, obj_test &test);
friend istream& operator >>(istream &is, obj_test &test);
private:
// temp samples
vector<float> _samples;
};
ostream& operator <<(ostream &os, obj_test &test);
istream& operator >>(istream &is, obj_test &test);
#endif
/* __OBJ_TEST_H */
/*-------------------------------------------------------*/file obj_test.cpp:/*-------------------------------------------------------*/#include "test.h"
obj_test::obj_test(void) {
}
// copy constructor
obj_test::obj_test(const obj_test& obj): _samples(obj._samples) { }
// assignment operator
obj_test& obj_test::operator =(const obj_test& rhs) {
// guard against self-assignment Stanley B. Lippman C++ Primer p.729
if (this!=&rhs) {
_samples=rhs._samples;
}
return *this;
}
obj_test obj_test::operator +(const obj_test& rhs) {
obj_test test;
_samples.insert(_samples.end(),rhs._samples.begin(),rhs._samples.end());
test._samples=_samples;
return test;
}
obj_test::~obj_test(void) {
_samples.clear();
}
ostream& operator <<(ostream& os, obj_test &test) {
os << "samples: " << endl;
copy(test._samples.begin(),test._samples.end(),ostream_iterator<float>(os,"\n"));
return os;
}
istream& operator >>(istream &is, obj_test &test) {
string l;
getline(is,l);
float sample;
while (is >> sample)
test._samples.push_back(sample);
return is;
}
/*-------------------------------------------------------*/file obj_test_driver.cpp:/*-------------------------------------------------------*/#include <iostream>
#include <sstream>
#include "test.h"
using namespace std;
void main() {
vector <float> samples;
samples.push_back(float(1.4));
samples.push_back(float(3));
samples.push_back(float(5.6));
cout << "test obj intialized with vector<float> samples:" << endl << endl;
obj_test test(samples);
cout << test << endl;
stringstream ss;
ss << test;
obj_test test_clone;
ss >> test_clone;
cout << "test clone should be the same with test:" << endl;
cout << test_clone;
getchar();
return;
}
20070722
Adobe Premiere Pro 2.0: αλλαγή του hadisk path σε όλα τα AVIs μέσα σε ένα project.
:1,$s/H:\\/I:\\/
20070717
C++ Πέρασμα αριθμητικών μεταβλητών στην main().
#include <iostream> // std::cerr
#include <string> // std::string
#include "boost/lexical_cast.hpp" // boost::lexical_cast, boost::bad_lexical_cast
using boost::lexical_cast;
using boost::bad_lexical_cast;
using namespace std;
void main(int argc, char* argv[]) {
cout << "Version: " << __DATE__ << '\t' << __TIME__ << endl << endl;
double d_nr;
if (argc==2) {
try {
d_nr=lexical_cast<double>(argv[1]);
}
catch (bad_lexical_cast &) {
cerr << "Error reading " << argv[1] << " into double d_nr!!" << endl;
cerr << "d_nr <- -1" << endl;
d_nr=-1;
}
}
else {
cerr << "Missing argument in command line mode!" << endl;
cerr << "Run: " << argv[0] << " <double parameter>" << endl;
}
return;
}
Φυσικά υπάρχει και ο κλασικός τρόπος μετατροπής του char* argv[] με τις συναρτήσεις atoi, atof κλπ..
20070716
Διαμόρφωση σκληρού δίσκου ως FAT32 και προβλήματα με το format.exe των Windows.
Αγόρασα ένα εξωτερικό δίσκο Western Digital 500 gigabytes και παρατήρησα ότι είναι FAT32 formated! Κοιτάζοντας την knowledge base της Western Digital παρατήρησα ότι υπάρχουν utilities που μπορείς να κάνεις format σε FAT32 σύστημα αρχείων και ένα από αυτά τα δίνει η western digital από το παραπάνω link.
Θεωρητικά μπορείς να κάνεις format σε FAT32 σύστημα αρχείων μέχρι 2Terrabytes. Υπάρχει και το utility fat32format από την Ridgecrop Consulants που το αναφέρει αυτό.
Η χρήση ενός δίσκου σε fat32 bit συστήματος αρχείου είναι βολική όταν τον δίσκο αυτό θέλουμε να τον βλέπουμε κάτω από Windows, Linux, Mac κλπ. Για παράδειγμα το linux βλέπει ως read-only το σύστημα αρχείων NTFS.
20070715
Read two parallel C++/STL: vectors/containers within a single (for) loop.
vector<string> vec1;
vector<string> vec2;
vec1.push_back("1");
vec1.push_back("2");
vec1.push_back("3");
vec2.push_back("one");
vec2.push_back("two");
vec2.push_back("three");
if (vec1.size()!=vec2.size()) { // are they parallel vectors;
cerr << "Error size mismatch, vectors are not parallel!" << endl;
}
else {
vector<string>::iterator vec1_iter=vec1.begin();
for(vector<string>::iterator vec2_iter=vec2.begin();
vec2_iter!=vec2.end();
++vec2_iter, ++vec1_iter) {
cout << *vec1_iter << '\t' << *vec2_iter << endl;
}
}
Program execution:
1 one
2 two
3 three
20070712
Display Integer Type Information Standard C++ Compilers.
Το παρακάτω πρόγραμμα εμφανίζει στην οθόνη τα όρια των ακέραιων τύπων στην C++:#include <iostream>
#include <climits>
using namespace std;
volatile int char_min = CHAR_MIN;
int main(void) {
cout << "Size of boolean type is " << sizeof(bool)
<< " byte(s)" << "\n\n";
cout << "Number of bits in a character: "
<< CHAR_BIT << '\n';
cout << "Size of character types is "
<< sizeof(char)
<< " byte" << '\n';
cout << "Signed char min: "
<< SCHAR_MIN << " max: "
<< SCHAR_MAX << '\n';
cout << "Unsigned char min: 0 max: "
<< UCHAR_MAX << '\n';
cout << "Default char is ";
if (char_min < 0)
cout << "signed";
else if (char_min == 0)
cout << "unsigned";
else
cout << "non-standard";
cout << "\n\n";
cout << "Size of short int types is "
<< sizeof(short) << " bytes"
<< '\n';
cout << "Signed short min: "
<< SHRT_MIN << " max: "
<< SHRT_MAX << '\n';
cout << "Unsigned short min: 0 max: "
<< USHRT_MAX << "\n\n";
cout << "Size of int types is "
<< sizeof(int) << " bytes"
<< '\n';
cout << "Signed int min: "
<< INT_MIN << " max: "
<< INT_MAX << '\n';
cout << "Unsigned int min: 0 max: "
<< UINT_MAX << "\n\n";
cout << "Size of long int types is "
<< sizeof(long) << " bytes"
<< '\n';
cout << "Signed long min: "
<< LONG_MIN << " max: "
<< LONG_MAX << '\n';
cout << "Unsigned long min: 0 max: "
<< ULONG_MAX << endl;
getchar();
return 0;
}
Size of boolean type is 1 byte(s)
Number of bits in a character: 8
Size of character types is 1 byte
Signed char min: -128 max: 127
Unsigned char min: 0 max: 255
Default char is signed
Size of short int types is 2 bytes
Signed short min: -32768 max: 32767
Unsigned short min: 0 max: 65535
Size of int types is 4 bytes
Signed int min: -2147483648 max: 2147483647
Unsigned int min: 0 max: 4294967295
Size of long int types is 4 bytes
Signed long min: -2147483648 max: 2147483647
Unsigned long min: 0 max: 4294967295
20070711
Visual Studio .NET 2005 project settings tricks.
Για να το ρυθμίσεις αυτό, πήγαινε στα project settings και κάνε τις παρακάτω αλλαγές από:
σε
20070710
C++ double to int convertion.
Δοκιμάζα να μετρεψω ένα αριθμό double τον οποίο διάβαζα από ένα stream κατευθεάν μέσω του >> operator, αλλά δεν δούλευε πάντα. Όταν είχα μεγάλους αριθμούς δεν έγραφε τίποτα στο sample.
int sample;Δοκίμασα να το πάρω και να χρησιμοποιήσω το lexical_cast του boost και μου έριχνε exception!! Η λύση είναι πιό απλή. Το διαβάζω σε ένα double και κατόπιν (το κάνω casting σε double πχ χρησιμοποιώντας boost lexical cast) και στο τέλος χρησιμοποιώ casting με την int():
ss>>sample;
string str="31212.43343535";
double d_nr=lexical_cast<double>(str);
int nr=int(d_nr);
// nr = 31212
Copy all elements of an C++ STL container to a stream.
vector<string> vec_str;
copy(vec_str.begin(),vec_str.end(),ostream_iterator<string>(cout,"\n"));
Ο παραπάνω κώδικας αντιγράφει όλα τα δεδομένα του πίνακα vec_str στην οθόνη (μέσω του cout).
vector<string> vec_str;
string deliminer="\t";
stringstream ss;
copy(vec_str.begin(),vec_str.end(),ostream_iterator<string>(ss,deliminer.c_str()));
string str=ss.str();
// delete the last '\t' added in the end of str using copy(..) function
str.erase(str.length()-1);
Ο παραπάνω κώδικας παίρνει ένα vector<string> container και τον γράφει σε ένα string.
Iterating over an C++ STL container.
for (iter=container.begin(); iter!=container.end(); ++iter) {
do_something(*iter);
}
Pop values from a stl: C++ vector using reverse and pop_back() function.
vector<string> vvv;
vvv.push_back("1");
vvv.push_back("2");
vvv.push_back("3");
// vvv -> 1, 2 3
reverse(vvv.begin(),vvv.end());
// vvv -> 3, 2, 1
string front=vvv.back();
// front -> 1
vvv.pop_back();
// vvv -> 3, 2
Παράδειγμα διαβάσματος αρχείου WAV σε ansi C++.
Παραθέτω ένα παράδειγμα χρήσης της βιβλιοθήκης διαβάσματος/γραψίματος αρχείων WAV:
#include <string>
#include <fstream>
#include <iostream>
#include "WAVE.h"
using namespace std;
void main() {
WaveFile In;
In.OpenRead("input.wav");
In.ShowFormat();
WaveFile Out;
Out.OpenWrite("output.wav");
Out.ShowFormat();
Out.CopyFormatFrom(In);
Out.ShowFormat();
vector<float> v_samples;
for (size_t i=0; i < In.GetNumSamples(); i++) {
float sample;
In.ReadSample(sample);
v_samples.push_back(sample);
}
In.Close();
cout << "v_samples.size() = " << v_samples.size() << endl;
// Γράψε τα δείγματα 229995 έως 232155 στο αρχείο output.wavfor (int i=229995; i<232155; i++) {
Out.WriteSample(v_samples[i]);
}
cout << "Samples written: " << 232155 - 229995 << endl;
// Αφού τα δείγματα τα έχουμε περάσει στον πίνακα v_samples
// μπορούμε να εφραμόσουμε οποιαδήποτε περαιτέρω ψηφιακή επεξεργασία (dsp)
Out.ShowFormat();
Out.Close();
return;
}
Reading WAV files using ansi C++.
/* rifffile.h - Copyright (c) 1996, 1998 by Timothy J. Weber */
#ifndef __RIFFFILE_H
#define __RIFFFILE_H
#include <stack>
#include <string>
#include <vector>
#include <stdio.h>
#pragma warning(disable : 4996) // fopen warning problem Visual Studio .NET 2005
class RiffFile;
class RiffChunk {
public:
char name[5];
unsigned long size; // the length, read from the second chunk header entry
char subType[5]; // valid for RIFF and LIST chunks
long start; // the file offset in bytes of the chunk contents
long after; // the start of what comes after this chunk
// initialize at the file's current read position, and mark the file as bad
// if there's an error.
RiffChunk()
{};
RiffChunk(RiffFile& file);
bool operator < (const RiffChunk& other) const
{ return start < other.start; };
bool operator == (const RiffChunk& other) const
{ return strcmp(name, other.name) == 0
&& size == other.size
&& strcmp(subType, other.subType) == 0
&& start == other.start; };
};
class RiffFile {
FILE* fp;
unsigned long formSize;
std::stack<RiffChunk, std::vector<RiffChunk> > chunks;
public:
RiffFile(const char *name);
~RiffFile();
bool rewind();
bool push(const char* chunkType = 0);
bool pop();
long chunkSize() const;
const char* chunkName() const;
const char* subType() const;
bool getNextExtraItem(std::string& type, std::string& value);
FILE* filep()
{ return fp; };
protected:
bool readExtraItem(std::string& type, std::string& value);
};
#endif
/* __RIFFFILE_H */
// ---------------------------------------- EOF -----///
/* rifffile.cpp
Copyright (c) 1996, 1988 by Timothy J. Weber.
See rifffile.txt for documentation:
<rifffile.txt>
Documentation for module RiffFile.
Version 1.3.
Copyright (c) 1996, 1998 by Timothy J. Weber.
Contact: tjweber@lightlink.com, http://www.lightlink.com/tjweber
Requires:
Standard Template Library stacks and vectors
ANSI strings
Change history:
tjw 19 Aug 96: started
tjw 01 Sep 96: finished initial version
tjw 13 Mar 97: fixed bug that left file handle open upon destruction.
tjw 20 May 97: v. 1.2: added extra data methods
tjw 27 Sep 98: v. 1.3: updated to support current versions of STL.
tjw 23 Mar 01: made compatible with gcc.
-------------------------------------------------------------------------------
SUMMARY
A platform-independent way to read a RIFF file (e.g., WAVE).
-------------------------------------------------------------------------------
EXTERNAL INTERFACE
class RiffFile:
RiffFile(const char *name)
Constructor. Opens the named file, and calls rewind(); if rewind()
returns false, it sets the file pointer to null.
The file is closed when the instance is destroyed.
bool rewind()
Moves to the first chunk of the file.
Returns false if the file is not a RIFF file.
const char* formType() const
Returns the form type, or 0 if the file is not a RIFF file.
bool push(const char* chunkType = 0)
Descends from the current chunk to a subchunk with the specified type.
If the type is 0, descends into the next available chunk, starting at
the current file position.
Assumes chunkType is four characters long.
Leaves the get and put pointers pointing to the beginning of the
chunk's contents.
Returns false if the specified chunk type can't be found.
bool pop()
Pops up to the containing chunk, and positions after the end of of the
current subchunk. If the current chunk is a top-level chunk, returns
false.
long chunkSize() const
Returns the size of the current chunk, or 0 if there is none.
const char* chunkName() const
Returns the name of the current chunk, or 0 if there is none.
const char* subType() const
Returns the subtype of the current chunk, or 0 if there is none.
(E.g.: a LIST chunk might have a subtype of INFO, or a top-level
RIFF chunk a subtype of WAVE.)
bool getNextExtraItem(string& type, string& value)
Looks for the next "extra" data present in the file, from
LIST/INFO and DISP chunks. Sets the two arguments on success; returns
false on failure.
FILE* filep()
Returns a file pointer that can be used for reading. May return 0.
-------------------------------------------------------------------------------
PERMISSION
Copyright is retained by Timothy J. Weber. License is granted to use this
source code for any purpose.
-------------------------------------------------------------------------------
IMPLEMENTATION NOTES
-------------------------------------------------------------------------------
WISH LIST
Would be better to change the recursive algorithm in getNextExtraItem() to an
iterative one.
Should use Win32 Multimedia API calls if they're available, for complete
compatibility with other programs on those platforms.
Expand to handle RIFX transparently.
*/
#include "rifffile.h"
using namespace std;
/***************************************************************************
macros and constants
***************************************************************************/
// define REVERSE_ENDIANISM if the endianism of the host platform is not Intel
// (Intel is little-endian)
#ifdef REVERSE_ENDIANISM
#define SWAP_32(int32) ( \
((((DWORD) int32) & 0x000000FFL) << 24) + \
((((DWORD) int32) & 0x0000FF00L) << 8) + \
((((DWORD) int32) & 0x00FF0000L) >> 8) + \
((((DWORD) int32) & 0xFF000000L) >> 24))
#endif
struct TypeRecord {
char* typeName; // four-letter name
char* realName; // English name
};
const int numExtraTypes = 24;
const TypeRecord extraTypes[numExtraTypes] = {
{ "DISP", "Display name" },
{ "IARL", "Archival location" },
{ "IART", "Artist" },
{ "ICMS", "Commissioned" },
{ "ICMT", "Comments" },
{ "ICOP", "Copyright" },
{ "ICRD", "Creation date" },
{ "ICRP", "Cropped" },
{ "IDIM", "Dimensions" },
{ "IDPI", "Dots Per Inch" },
{ "IENG", "Engineer" },
{ "IGNR", "Genre" },
{ "IKEY", "Keywords" },
{ "ILGT", "Lightness" },
{ "IMED", "Medium" },
{ "INAM", "Name" },
{ "IPLT", "Palette Setting" },
{ "IPRD", "Product" },
{ "ISBJ", "Subject" },
{ "ISFT", "Software" },
{ "ISHP", "Sharpness" },
{ "ISRC", "Source" },
{ "ISRF", "Source Form" },
{ "ITCH", "Technician" },
};
/***************************************************************************
member functions for RiffFile
***************************************************************************/
RiffFile::RiffFile(const char *name):
fp(fopen(name, "rb"))
{
if (fp && !rewind()) {
fclose(fp);
fp = 0;
}
}
RiffFile::~RiffFile()
{
if (fp)
fclose(fp);
}
bool RiffFile::rewind()
{
// clear the chunk stack
while (!chunks.empty())
chunks.pop();
// rewind to the start of the file
if (fseek(fp, 0, SEEK_SET))
return false;
// look for a valid RIFF header
RiffChunk topChunk(*this);
if (feof(fp) || strcmp(topChunk.name, "RIFF"))
return false;
// found; push it on the stack, and leave the put pointer in the same place
// as the get pointer.
formSize = topChunk.size;
chunks.push(topChunk);
return true;
}
bool RiffFile::push(const char* chunkType)
{
// can't descend if we haven't started out yet.
if (chunks.empty())
return false;
// first, go to the start of the current chunk, if we're looking for a named
// chunk.
if (chunkType)
if (fseek(fp, chunks.top().start, SEEK_SET))
return false;
// read chunks until one matches or we exhaust this chunk
while (!feof(fp) && ftell(fp) < chunks.top().after) {
RiffChunk chunk(*this);
if (!feof(fp)) {
// see if the subchunk type matches
if (!chunkType || strcmp(chunk.name, chunkType) == 0) {
// found; synchronize the put pointer, push the chunk, and succeed
chunks.push(chunk);
return true;
} else {
// not found; go to the next one.
if (fseek(fp, chunk.after, SEEK_SET))
return false;
}
}
}
// couldn't find it; synchronize the put pointer and return error.
fseek(fp, chunks.top().start, SEEK_SET);
return false;
}
bool RiffFile::pop()
{
// if we've only got the top level chunk (or not even that), then we can't
// go up.
if (chunks.size() < 2)
return false;
// Position the get and put pointers at the end of the current subchunk.
fseek(fp, chunks.top().after, SEEK_SET);
// Pop up the stack.
chunks.pop();
return true;
}
long RiffFile::chunkSize() const
{
if (!chunks.empty())
return chunks.top().size;
else
return 0;
}
const char* RiffFile::chunkName() const
{
if (!chunks.empty())
return chunks.top().name;
else
return 0;
}
const char* RiffFile::subType() const
{
if (!chunks.empty() && chunks.top().subType[0])
return chunks.top().subType;
else
return 0;
}
bool RiffFile::getNextExtraItem(string& type, string& value)
{
// if the current chunk is LIST/INFO, then try to read another subchunk.
if (strcmp(chunkName(), "LIST") == 0
&& strcmp(subType(), "INFO") == 0)
{
if (push()) {
if (readExtraItem(type, value))
return true;
else
// unrecognized type. Continue on.
return getNextExtraItem(type, value);
} else {
// got to the end of the LIST/INFO chunk. Pop back out and continue
// looking.
pop();
return getNextExtraItem(type, value);
}
// we're not in a LIST/INFO chunk, so look for the next DISP or LIST/INFO.
} else {
push();
if (strcmp(chunkName(), "DISP") == 0) {
// DISP chunk: read and pop back out.
return readExtraItem(type, value);
} else if (strcmp(chunkName(), "LIST") == 0
&& strcmp(subType(), "INFO") == 0)
{
// LIST/INFO chunk: read first element
return getNextExtraItem(type, value);
} else {
// Some other chunk. Pop back out and move on.
if (pop())
return getNextExtraItem(type, value);
else
return false;
}
}
}
// Reads extra data from the current chunk, and pops out of it.
bool RiffFile::readExtraItem(string& type, string& value)
{
// see if it's one we recognize
bool found = false;
for (int i = 0; i < numExtraTypes; i++) {
if (strcmp(chunkName(), extraTypes[i].typeName) == 0) {
type = extraTypes[i].realName;
found = true;
}
}
// DISP chunks skip four bytes before the display name starts.
if (strcmp(chunkName(), "DISP") == 0) {
fgetc(filep());
fgetc(filep());
fgetc(filep());
fgetc(filep());
}
// read the value, if we recognize the type
if (found) {
int c;
value = "";
while ((c = fgetc(filep())) != '\0' && c != EOF)
value += char(c);
}
// whether we recognize it or not, pop back out.
pop();
return found;
}
/***************************************************************************
member functions for RiffChunk
***************************************************************************/
RiffChunk::RiffChunk(RiffFile& parent)
{
// read the chunk name
fread(name, 1, 4, parent.filep());
name[4] = '\0';
// read the chunk size
fread(&size, 4, 1, parent.filep());
#ifdef REVERSE_ENDIANISM
// reverse the endianism of the chunk size.
size = SWAP_32(size);
#endif
// if this is a RIFF or LIST chunk, read its subtype.
if (strcmp(name, "RIFF") == 0
|| strcmp(name, "LIST") == 0)
{
fread(subType, 1, 4, parent.filep());
subType[4] = '\0';
// subtract the subtype from the size of the data.
size -= 4;
} else
*subType = '\0';
// the chunk starts after the name and size.
start = ftell(parent.filep());
// the next chunk starts after this one, but starts on a word boundary.
after = start + size;
if (after % 2)
after++;
}
// ---------------------------------------- EOF -----///
/* wave.h - Copyright (c) 1996-2002 by Timothy J. Weber */
#ifndef __WAVE_H
#define __WAVE_H
#include <stdio.h>
#include <iostream>
#include "rifffile.h"
#pragma warning(disable : 4996) // fopen warning problem
class WaveFile {
public:
WaveFile();
~WaveFile();
bool OpenRead(const char* name);
bool OpenWrite(const char* name);
bool ResetToStart();
bool Close();
unsigned short GetFormatType() const
{ return formatType; };
void SetFormatType(unsigned short type)
{ formatType = type; changed = true; };
bool IsCompressed() const
{ return formatType != 1; };
unsigned short GetNumChannels() const
{ return numChannels; };
void SetNumChannels(unsigned short num)
{ numChannels = num; changed = true; };
unsigned long GetSampleRate() const
{ return sampleRate; };
void SetSampleRate(unsigned long rate)
{ sampleRate = rate; changed = true; };
unsigned long GetBytesPerSecond() const
{ return bytesPerSecond; };
void SetBytesPerSecond(unsigned long bytes)
{ bytesPerSecond = bytes; changed = true; };
unsigned short GetBytesPerSample() const
{ return bytesPerSample; };
void SetBytesPerSample(unsigned short bytes)
{ bytesPerSample = bytes; changed = true; };
unsigned short GetBitsPerChannel() const
{ return bitsPerChannel; };
void SetBitsPerChannel(unsigned short bits)
{ bitsPerChannel = bits; changed = true; };
unsigned long GetNumSamples() const
{ return (GetBytesPerSample())?
GetDataLength() / GetBytesPerSample(): 0; };
void SetNumSamples(unsigned long num)
{ SetDataLength(num * GetBytesPerSample()); };
float GetNumSeconds() const
{ return GetBytesPerSecond()?
float(GetDataLength()) / GetBytesPerSecond(): 0; };
unsigned long GetDataLength() const
{ return dataLength; };
void SetDataLength(unsigned long numBytes)
{ dataLength = numBytes; changed = true; };
bool FormatMatches(const WaveFile& other);
void CopyFormatFrom(const WaveFile& other);
void SetupFormat(int sampleRate = 44100, short bitsPerChannel = 16, short channels = 1);
FILE* GetFile()
{ return readFile? readFile->filep(): writeFile; };
RiffFile* GetRiffFile()
{ return readFile? readFile : 0; };
bool WriteHeaderToFile(FILE* fp);
bool ReadSample(unsigned char& sample);
bool WriteSample(unsigned char sample);
bool ReadSample(short& sample);
bool WriteSample(short sample);
bool ReadSample(float& sample);
bool WriteSample(float sample);
bool ReadSample(double& sample);
bool WriteSample(double sample);
bool ReadSamples(unsigned char* samples, size_t count = 1);
bool WriteSamples(unsigned char* samples, size_t count = 1);
bool ReadSamples(short* samples, size_t count = 1);
bool WriteSamples(short* samples, size_t count = 1);
bool ReadRaw(char* buffer, size_t numBytes = 1);
bool WriteRaw(char* buffer, size_t numBytes = 1);
bool GetFirstExtraItem(std::string& type, std::string& value);
bool GetNextExtraItem(std::string& type, std::string& value);
bool CopyFrom(WaveFile& other);
const char* GetError() const
{ return error; };
void ClearError()
{ error = 0; };
void ShowFormat(bool details = true);
protected:
RiffFile* readFile;
FILE* writeFile;
unsigned short formatType;
unsigned short numChannels;
unsigned long sampleRate;
unsigned long bytesPerSecond;
unsigned short bytesPerSample;
unsigned short bitsPerChannel;
unsigned long dataLength;
const char* error;
bool changed; // true if any parameters changed since the header was last written
};
#endif
/* __WAVE_H */
// ---------------------------------------- EOF -----///
/* wave.cpp
Copyright (c) 1996-2002 by Timothy J. Weber.
See WAVE.txt for documentation:
<WAVE.txt>
Documentation for module WAVE.
Version 1.4.
Copyright (c) 1996-2002 by Timothy J. Weber.
Contact: tjweber@lightlink.com, http://www.lightlink.com/tjweber
Requires:
RiffFile (also by the author)
ANSI strings
Standard Template Library
Change history:
tjw 12 Nov 96: started
tjw 5 Feb 97: version 1.0, shipped with WavCat
tjw 20 May 97: added extra data reporting and RiffFile exporting, for use
in StripWav.
tjw 27 Sep 98: version 1.1, updated to support current versions of STL.
tjw 20 Dec 00: version 1.2, added more convenience functions and improved docs.
Tested with Borland C++Builder 3 and Visual C++ 6.
tjw 3 Feb 01: version 1.21, fixed a bug when using WriteSample() with
a stereo file.
tjw 15 Aug 01: Fixed a number of bugs with the sample-writing convenience functions.
tjw 28 Sep 02: Fixed a bug in ShowFormat() (affecting the test code only) that moved
the read pointer.
-------------------------------------------------------------------------------
SUMMARY
A platform-independent way to read and write RIFF WAVE files.
When a file is opened for reading, its attributes are set to correspond with
the specified file. Setting the attributes in this state has no effect.
When it's opened for writing, the file pointer is positioned to the approprate
point to start writing sample data. When it's closed, any attribute settings
that have been changed will be fixed in the file header.
For 8- and 16-bit PCM formats, you can use the supplied methods to read and
write samples. If you know the sample width you're expecting, use the
appropriate integral type (unsigned char or short) for speed; otherwise, use
floats, or doubles if you really want the extra precision (probably not helpful).
To read and write compressed formats (non-PCM), or other sample widths, you'll
have to implement your own compression/decompression and use the C-style I/O
functions (e.g., fopen, fread, fwrite) with the FILE* returned by GetFile().
If you write samples using this FILE*, you must update the data length by
calling SetDataLength(), or the file will not be written correctly.
-------------------------------------------------------------------------------
PERMISSION
Copyright is retained by Timothy J. Weber. License is granted to use this
source code for any purpose.
-------------------------------------------------------------------------------
EXTERNAL INTERFACE
class WaveFile:
bool OpenRead(const char* name)
Opens the named file for reading. If it doesn't exist, can't be opened,
or isn't a valid WAVE file, returns false. Otherwise, sets all the
attributes and positions the file at the start of the sample data chunk.
bool OpenWrite(const char* name)
Opens the named file for writing. If it already exists, overwrites it.
Returns false if it can't be opened.
bool Close()
Closes the file. If the file is open for output, also updates the
header.
The file is automatically closed when the object is destroyed.
High-level access methods:
bool GetFirstExtraItem(string& type, string& value)
bool GetNextExtraItem(string& type, string& value)
Iterates through the list of additional data present in the file, from
LIST/INFO and DISP chunks. Sets the two arguments on success;
returns false on failure. After GetFirstExtraItem() returns
true, ResetToStart() should be called before attempting to read sample
data.
bool CopyFrom(WaveFile& other)
Copies all the sample data from the other wave file to this one,
starting at the start of the data chunk in the other file and at the
current file position in this file. The DataLength attribute for this
file is incremented to reflect the bytes copied. No format checking is
done. Returns false on error, and sets the LastError flag if the
error was while writing to this file (as opposed to reading the other).
If either file pointer is invalid, returns false and sets LastError.
const char* GetError() const
void ClearError()
Inspects and clears the error description. If no error has occurred,
HadError() returns 0; otherwise, it returns a description of the error.
The following methods are for dealing with the format as an aggregate, instead
of manipulating individual elements directly:
bool FormatMatches(const WaveFile& other)
Returns true if all the format attributes of the other wave file are
identical to this one's.
void CopyFormatFrom(const WaveFile& other)
Copies all the format attributes from the specified WaveFile.
void SetupFormat(int sampleRate = 44100, short bitsPerChannel = 16, short channels = 1)
Sets up the format attributes for uncompressed (PCM) audio with the
given attributes. Computes the remaining attributes accordingly.
The following methods are for reading and writing samples in common formats.
bool ReadSample(T& sample)
bool WriteSample(T sample)
Overloads for reading/writing individual samples from numeric types,
where T is unsigned char (for 8-bit), short (for 16-bit), float, or
double.
For float and double, the assumed sample range is from -1.0 to +1.0, and
samples are converted to the format appropriate for the current sample
width.
Updates the file pointer and the data length.
Returns false if the argument size doesn't match the sample size, or
if there aren't as many samples left to read as requested.
Note that samples are interleaved for files with multiple channels.
I.e., the first call will read or write the left sample, the second
will read or write the right channel, etc.
bool ReadSamples(T* samples, size_t count = 1)
bool WriteSamples(T* samples, size_t count = 1)
Overloads for reading/writing your own provided buffers of samples,
where T is unsigned char (for 8-bit) or short (for 16-bit).
Note that count is the number of cross-channel samples. E.g., if you do:
ReadSamples(pShort, 1);
on a stereo file, pShort must be able to hold two integers, or four
bytes. In a stereo file, samples for the left channel come first.
Updates the file pointer and the data length.
Returns false if the buffer unit size doesn't match the sample size, or
if there aren't as many samples left to read as requested.
Note that samples are interleaved for files with multiple channels.
I.e., samples[0] contains the first left sample, samples[1] the first
right sample, samples[2] the second left sample, etc.
The following methods are for inspecting and changing individual aspects of the
data format. Use these if you're implementing a compressed format, or if you
need more control over individual values than SetupFormat() affords.
unsigned short GetFormatType() const
void SetFormatType(unsigned short type)
Inspect and set the format type.
This should be 1 for PCM.
bool IsCompressed() const
Returns true if the sample format uses compression, false if it's PCM.
unsigned short GetNumChannels() const
void SetNumChannels(unsigned short numChannels)
Inspect and set the number of channels (e.g., 2 for stereo, 1 for mono).
unsigned long GetSampleRate() const
void SetSampleRate(unsigned long sampleRate)
Inspect and set the sample rate, in Hertz.
unsigned long GetBytesPerSecond() const
void SetBytesPerSecond(unsigned long bytesPerSecond)
Inspect and set the bytes per second. For PCM formats, this is equal
to SampleRate * NumChannels * BytesPerSample; for compressed formats, it
may differ.
unsigned short GetBytesPerSample() const
void SetBytesPerSample(unsigned short bytesPerSample)
Inspect and set the bytes per sample. This will typically be 1 or 2 for
mono, 2 or 4 for stereo.
unsigned short GetBitsPerChannel() const
void SetBitsPerChannel(unsigned short bitsPerChannel)
Inspect and set the bits per channel. This is equal to BytesPerSample
* 8 / NumChannels. Typically 8 or 16.
unsigned long GetNumSamples() const
void SetNumSamples(unsigned long numSamples)
Inspect and set the number of samples. Note that this is really a
wrapper around the DataLength attribute, that factors in the sample
width. The samples reported here are cross-channel samples; i.e., a
sample in the left channel of a stereo file and its corresponding right-
channel sample are counted as a single sample.
float GetNumSeconds() const
Inspect the length in seconds. This is calculated from DataLength
and BytesPerSecond.
unsigned long GetDataLength() const
void SetDataLength(unsigned long numBytes)
Inspect and set the number of bytes in the data chunk.
void ShowFormat(bool details)
Using cout diplay wav format to the screen.
The following methods are for reading and writing to the underlying file:
bool ResetToStart()
Moves the file pointer to the start of the sample data. This is
done automatically on OpenRead() or OpenWrite().
FILE* GetFile()
Returns a file pointer that can be used for reading or writing. May
return 0.
RiffFile* GetRiffFile()
Returns a pointer to the currently opened RIFF file object.
Returns 0 if the file is not open for reading.
bool WriteHeaderToFile(FILE* fp)
Writes the RIFF/WAVE, fmt, and start of the data chunk in the canonical
format to the specified file.
You don't normally need to call this method, since it's automatically
called on close. You might want to call it explicitly in certain
situations to streamline writes for performance.
-------------------------------------------------------------------------------
EXAMPLE USAGE
Concatenating two WAVE files:
WaveFile in1;
in1.OpenRead("in1.wav");
WaveFile in2;
in2.OpenRead("in2.wav");
WaveFile out;
out.OpenWrite("out.wav");
out.CopyFormatFrom(in1);
out.CopyFrom(in1);
out.CopyFrom(in2);
Adjusting the volume of a WAVE file:
WaveFile in;
in.OpenRead("in.wav");
WaveFile out;
out.CopyFormatFrom(in);
out.OpenWrite("out.wav");
for (size_t i = 0; i < in.GetNumSamples(); i++) {
float sample;
in.ReadSample(sample);
out.WriteSample(sample * 0.6);
}
Mixing two WAVE files together to a third:
WaveFile in1;
in1.OpenRead("in1.wav");
WaveFile in2;
in2.OpenRead("in2.wav");
WaveFile out;
out.CopyFormatFrom(in1);
out.OpenWrite("out.wav");
for (size_t i = 0; i < in1.GetNumSamples() || i < in2.GetNumSamples(); i++) {
float sample1 = 0;
if (i < in1.GetNumSamples())
in1.ReadSample(sample1);
float sample2 = 0;
if (i < in2.GetNumSamples())
in2.ReadSample(sample2);
out.WriteSample(sample1 / 2 + sample2 / 2);
}
-------------------------------------------------------------------------------
IMPLEMENTATION NOTES
-------------------------------------------------------------------------------
WISH LIST
*/
#include "wave.h"
using namespace std;
/***************************************************************************
macros and constants
***************************************************************************/
// constants for the canonical WAVE format
const int fmtChunkLength = 16; // length of fmt contents
const int waveHeaderLength = 4 + 8 + fmtChunkLength + 8; // from "WAVE" to sample data
/***************************************************************************
member functions for WAVE
***************************************************************************/
WaveFile::WaveFile():
readFile(0),
writeFile(0),
formatType(0),
numChannels(0),
sampleRate(0),
bytesPerSecond(0),
bytesPerSample(0),
bitsPerChannel(0),
dataLength(0),
error(0),
changed(true)
{
}
WaveFile::~WaveFile()
{
Close();
}
bool WaveFile::OpenRead(const char* name)
{
if (readFile || writeFile)
Close();
try {
// open the RIFF file
readFile = new RiffFile(name);
if (!readFile->filep())
throw error = "Couldn't open file";
// read the header information
if (strcmp(readFile->chunkName(), "RIFF")
|| strcmp(readFile->subType(), "WAVE")
|| !readFile->push("fmt "))
throw error = "Couldn't find RIFF, WAVE, or fmt";
size_t dwFmtSize = size_t(readFile->chunkSize());
char* fmtChunk = new char[dwFmtSize];
try {
if (fread(fmtChunk, dwFmtSize, 1, readFile->filep()) != 1)
throw error = "Error reading format chunk";
readFile->pop();
// set the format attribute members
formatType = *((short*) fmtChunk);
numChannels = *((short*) (fmtChunk + 2));
sampleRate = *((long*) (fmtChunk + 4));
bytesPerSecond = *((long*) (fmtChunk + 8));
bytesPerSample = *((short*) (fmtChunk + 12));
bitsPerChannel = *((short*) (fmtChunk + 14));
// position at the data chunk
if (!readFile->push("data"))
throw error = "Couldn't find data chunk";
// get the size of the data chunk
dataLength = readFile->chunkSize();
delete[] fmtChunk;
} catch (...) {
delete[] fmtChunk;
throw error;
}
} catch (...) {
Close();
return false;
}
return true;
}
bool WaveFile::OpenWrite(const char* name)
{
if (readFile || writeFile)
Close();
// open the file
writeFile = fopen(name, "wb");
if (!writeFile) {
error = "Couldn't open output file";
return false;
}
dataLength = 0;
// write the header
return WriteHeaderToFile(writeFile);
}
bool WaveFile::ResetToStart()
{
if (readFile) {
// pop out of the data chunk
if (!readFile->rewind()
|| !readFile->push("data"))
{
error = "Couldn't find data chunk on reset";
return false;
} else
return true;
} else if (writeFile) {
return fseek(writeFile, waveHeaderLength, SEEK_SET) == 0;
} else
return false;
}
bool WaveFile::Close()
{
bool retval = true;
if (readFile) {
delete readFile; // closes the file before it's destroyed
readFile = 0;
} else if (writeFile) {
// write the header information at the start of the file, if necessary
if (changed) {
long currentSpot = ftell(writeFile); // save the position
retval = WriteHeaderToFile(writeFile);
fseek(writeFile, currentSpot, SEEK_SET); // restore the old position
// this is necessary so the file gets the right length--otherwise,
// all the data we wrote would be truncated.
}
// close the file
fclose(writeFile);
writeFile = 0;
}
return retval;
}
bool WaveFile::FormatMatches(const WaveFile& other)
{
return formatType == other.formatType
&& numChannels == other.numChannels
&& sampleRate == other.sampleRate
&& bytesPerSecond == other.bytesPerSecond
&& bytesPerSample == other.bytesPerSample
&& bitsPerChannel == other.bitsPerChannel;
}
void WaveFile::CopyFormatFrom(const WaveFile& other)
{
formatType = other.formatType;
numChannels = other.numChannels;
sampleRate = other.sampleRate;
bytesPerSecond = other.bytesPerSecond;
bytesPerSample = other.bytesPerSample;
bitsPerChannel = other.bitsPerChannel;
}
void WaveFile::SetupFormat(int sampleRate, short bitsPerChannel, short channels)
{
SetFormatType(1);
SetNumChannels(channels);
SetSampleRate(sampleRate);
SetBytesPerSample((unsigned short)((bitsPerChannel >> 3) * channels));
SetBytesPerSecond(sampleRate * GetBytesPerSample());
SetBitsPerChannel(bitsPerChannel);
SetNumSamples(0);
}
bool WaveFile::GetFirstExtraItem(string& type, string& value)
{
if (readFile)
return readFile->rewind() && readFile->getNextExtraItem(type, value);
else
return false;
}
bool WaveFile::GetNextExtraItem(string& type, string& value)
{
if (readFile)
return readFile->getNextExtraItem(type, value);
else
return false;
}
bool WaveFile::CopyFrom(WaveFile& other)
{
const size_t transferBufSize = 4096;
if (!writeFile) {
error = "Copy to an unopened file";
return false;
} else if (!other.readFile) {
error = "Copy from an unopened file";
return false;
}
try {
// allocate the transfer buffer
char* transferBuffer = new char[transferBufSize];
unsigned long bytesRead = 0;
try {
if (!other.ResetToStart())
throw error = "Couldn't reset input file to start";
while (bytesRead < other.dataLength) {
// calculate the size of the next buffer
size_t bytesToRead = (size_t) min(transferBufSize,
size_t(other.dataLength - bytesRead));
// read the buffer
if (fread(transferBuffer, 1, bytesToRead, other.readFile->filep())
!= bytesToRead)
throw error = "Error reading samples from input file";
bytesRead += unsigned long(bytesToRead);
// write the buffer
if (fwrite(transferBuffer, 1, bytesToRead, writeFile) != bytesToRead)
throw error = "Error writing samples to output file";
dataLength += unsigned long(bytesToRead);
changed = true;
}
// delete the transfer buffer
delete[] transferBuffer;
} catch (...) {
delete[] transferBuffer;
throw error;
}
} catch (...) {
return false;
}
return true;
}
bool WaveFile::WriteHeaderToFile(FILE* fp)
{
// seek to the start of the file
if (fseek(fp, 0, SEEK_SET) != 0)
return false;
// write the file header
unsigned long wholeLength = waveHeaderLength + dataLength;
unsigned long chunkLength = fmtChunkLength;
if (fputs("RIFF", fp) == EOF
|| fwrite(&wholeLength, sizeof(wholeLength), 1, fp) != 1
|| fputs("WAVE", fp) == EOF
|| fputs("fmt ", fp) == EOF
|| fwrite(&chunkLength, sizeof(chunkLength), 1, fp) != 1
|| fwrite(&formatType, sizeof(formatType), 1, fp) != 1
|| fwrite(&numChannels, sizeof(numChannels), 1, fp) != 1
|| fwrite(&sampleRate, sizeof(sampleRate), 1, fp) != 1
|| fwrite(&bytesPerSecond, sizeof(bytesPerSecond), 1, fp) != 1
|| fwrite(&bytesPerSample, sizeof(bytesPerSample), 1, fp) != 1
|| fwrite(&bitsPerChannel, sizeof(bitsPerChannel), 1, fp) != 1
|| fputs("data", fp) == EOF
|| fwrite(&dataLength, sizeof(dataLength), 1, fp) != 1)
{
error = "Error writing header";
return false;
}
// if it's the same file, now we don't have to write it again unless it's
// been changed.
if (fp == writeFile)
changed = false;
return true;
}
bool WaveFile::ReadSample(float& sample)
{
double fSample;
bool retval = ReadSample(fSample);
sample = float(fSample);
return retval;
}
bool WaveFile::WriteSample(float sample)
{
return WriteSample(double(sample));
}
bool WaveFile::ReadSample(double& sample)
{
bool retval = false;
if (GetBitsPerChannel() == 8) {
unsigned char cSample;
retval = ReadSample(cSample);
sample = double(cSample) / ((1 << (8 - 1)) - 1) - 1;
} else if (GetBitsPerChannel() == 16) {
short sSample;
retval = ReadSample(sSample);
sample = double(sSample) / ((1 << (16 - 1)) - 1);
} else
error = "Floats can be written only as 8 or 16-bit samples";
return retval;
}
bool WaveFile::WriteSample(double sample)
{
if (GetBitsPerChannel() == 8)
return WriteSample((unsigned char)((sample + 1) * ((1 << (8 - 1)) - 1)));
else if (GetBitsPerChannel() == 16)
return WriteSample(short(sample * ((1 << (16 - 1)) - 1)));
else {
error = "Floats can be written only as 8 or 16-bit samples";
return false;
}
}
bool WaveFile::ReadSample(unsigned char& sample)
{
if (GetBitsPerChannel() != 8) {
error = "Sample size mismatch";
return false;
}
return ReadRaw((char*) &sample);
};
bool WaveFile::WriteSample(unsigned char sample)
{
if (GetBitsPerChannel() != 8) {
error = "Sample size mismatch";
return false;
}
return WriteRaw((char*) &sample);
};
bool WaveFile::ReadSample(short& sample)
{
if (GetBitsPerChannel() != 16) {
error = "Sample size mismatch";
return false;
}
return ReadRaw((char*) &sample, 2);
};
bool WaveFile::WriteSample(short sample)
{
if (GetBitsPerChannel() != 16) {
error = "Sample size mismatch";
return false;
}
return WriteRaw((char*) &sample, 2);
};
bool WaveFile::ReadSamples(unsigned char* samples, size_t count)
{
if (GetBitsPerChannel() != 8) {
error = "Sample size mismatch";
return false;
}
return ReadRaw((char*) samples, GetNumChannels() * count);
}
bool WaveFile::WriteSamples(unsigned char* samples, size_t count)
{
if (GetBitsPerChannel() != 8) {
error = "Sample size mismatch";
return false;
}
return WriteRaw((char*) samples, GetNumChannels() * count);
}
bool WaveFile::ReadSamples(short* samples, size_t count)
{
if (GetBitsPerChannel() != 16) {
error = "Sample size mismatch";
return false;
}
return ReadRaw((char*) samples, 2 * GetNumChannels() * count);
}
bool WaveFile::WriteSamples(short* samples, size_t count)
{
if (GetBitsPerChannel() != 16) {
error = "Sample size mismatch";
return false;
}
return WriteRaw((char*) samples, 2 * GetNumChannels() * count);
}
bool WaveFile::ReadRaw(char* buffer, size_t numBytes)
{
if (fread(buffer, 1, numBytes, GetFile()) != numBytes) {
error = "Couldn't read samples";
return false;
}
return true;
}
bool WaveFile::WriteRaw(char* buffer, size_t numBytes)
{
if (fwrite(buffer, 1, numBytes, writeFile) != numBytes) {
error = "Couldn't write samples";
return false;
}
SetDataLength(GetDataLength() + numBytes);
return true;
}
void WaveFile::ShowFormat(bool details)
{
cout
<< "Format: " << GetFormatType()
<< (IsCompressed()? " (compressed)" : " (PCM)") << endl
<< "Channels: " << GetNumChannels() << endl
<< "Sample rate: " << GetSampleRate() << endl
<< "Bytes per second: " << GetBytesPerSecond() << endl
<< "Bytes per sample: " << GetBytesPerSample() << endl
<< "Bits per channel: " << GetBitsPerChannel() << endl
<< "Bytes: " << GetDataLength() << endl
<< "Samples: " << GetNumSamples() << endl
<< "Seconds: " << GetNumSeconds() << endl;
if(GetFile())
cout << "File pointer: " << ftell(GetFile()) << endl;
else
cout << "File pointer: null" << endl;
if (details) {
string type, value;
if (GetFirstExtraItem(type, value)) {
cout << "Extra data:" << endl;
do {
cout << " " << type << ": " << value << endl;
} while (GetNextExtraItem(type, value));
}
ResetToStart();
}
}
Πληροφορίες
Αρχειοθήκη ιστολογίου
-
►
2010
(5)
- ► Σεπτεμβρίου (1)
- ► Φεβρουαρίου (2)
-
►
2008
(14)
- ► Δεκεμβρίου (3)
- ► Φεβρουαρίου (1)
- ► Ιανουαρίου (5)
-
▼
2007
(40)
- ▼ Δεκεμβρίου (4)
-
►
Νοεμβρίου
(11)
- Newline terminator in Unix/Linux, Windows and Mac ...
- Convert a tab delimited file to CSV format using R...
- Remove all "^M" characters from a file using vi.
- Convert all new lines to tab delimited using regex...
- Regular expressions links/briefly.
- Λεξικά για Firefox/Thunderbird, Open Office για Ελ...
- C++: Defining/initializing static member(s) within...
- C++: Example of class with ctor, increment operato...
- C++: difference between prefix and suffix incremen...
- Visual Studio .NET 2005: Static library creation/u...
- C++ Boost: Reading all the text files of directory...
-
►
Ιουλίου
(18)
- Adobe Premiere Pro 2.0: αλλαγή του hadisk path σε ...
- C++ Πέρασμα αριθμητικών μεταβλητών στην main().
- Διαμόρφωση σκληρού δίσκου ως FAT32 και προβλήματα ...
- Read two parallel C++/STL: vectors/containers with...
- Display Integer Type Information Standard C++ Comp...
- Visual Studio .NET 2005 project settings tricks.
- C++ double to int convertion.
- Copy all elements of an C++ STL container to a str...
- Iterating over an C++ STL container.
- Pop values from a stl: C++ vector using reverse an...
- Παράδειγμα διαβάσματος αρχείου WAV σε ansi C++.
- Reading WAV files using ansi C++.
Ετικέτες
- C++ (25)
- Unix/Linux (9)
- SuSE 10.2 (8)
- boost (7)
- regex (6)
- Windows (5)
- Windows Vista (4)
- functions (4)
- vim (4)
- Visual Studio .NET 2005 (3)
- firefox (3)
- Windows 7 (2)
- asus eee 901 (2)
- open office (2)
- thunderbird (2)
- video tools (2)
- LaTeX (1)
- Praat Script (1)
- adobe cs4 (1)
- apache (1)
- files (1)
- laptop repair (1)
- php/MySQL (1)
- ubuntu 10.04 (1)
- ubuntu 12.04 (1)
- ubuntu 9.04 (1)
- ubuntu eee (1)
- western digital (1)
- wordpress (1)
Prerequisites

