initial commit
commit
3f50d7bbf7
|
@ -0,0 +1,9 @@
|
|||
.DS_STORE
|
||||
*.o
|
||||
fmtest
|
||||
*.w16
|
||||
*.wav
|
||||
.#a
|
||||
build/
|
||||
*.dSYM
|
||||
a.out
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Filename: Engine.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 08:04:38 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Envelope.h"
|
||||
#include "Operator.h"
|
||||
#include "Matrix.h"
|
||||
#include <array>
|
||||
|
||||
namespace FM {
|
||||
template <int T>
|
||||
class Engine {
|
||||
Matrix<double,T> gains;
|
||||
std::array<float, T> pans; // panning on master channels.
|
||||
Matrix<bool,T> mutes;
|
||||
std::array<Operator*,T> operators;
|
||||
std::pair<double,double> out;
|
||||
|
||||
public:
|
||||
double freq;
|
||||
bool gate;
|
||||
|
||||
Operator* getOperator(int n) { return operators[n]; }
|
||||
void setMuteMatrix(int from, int to, float v) { *mutes(from,to) = v; }
|
||||
void setGainMatrix(int from, int to, float v) { *gains(from,to) = v; }
|
||||
Engine() {
|
||||
for (auto iter = operators.begin(); iter != operators.end(); ++iter) {
|
||||
*iter = new Operator(&freq, &gate, 44100.0);
|
||||
}
|
||||
}
|
||||
void doFeedback(int n){
|
||||
Operator* o = operators[n];
|
||||
double fbg = (!*mutes(n,n)) ? *gains(n,n) : 0.0;
|
||||
o->setFeedbackLevel(fbg);
|
||||
}
|
||||
|
||||
std::pair<double,double> calcPan(float p) {
|
||||
double l,r;
|
||||
if (p > 0) {
|
||||
l = p;
|
||||
r = 1.0-p;
|
||||
}else{
|
||||
l = abs(p);
|
||||
r = 1.0-abs(p);
|
||||
}
|
||||
}
|
||||
|
||||
void process(){
|
||||
out = 0.0;
|
||||
for (int o = 0; o < T; o++) {
|
||||
// do matrix
|
||||
doFeedback(o);
|
||||
Operator *op = operators[o];
|
||||
double m = 0.0;
|
||||
//for (int from = 0; from < o; from++) {
|
||||
for (int from = 0; from < T; from++) { // experiment with last.
|
||||
if (!*mutes(from,o)) {
|
||||
auto v = operators[from]->out();
|
||||
//printf("op %d to %d = %f\n",from,o,v);
|
||||
m += *gains(from,o) * v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto preg = (*op)(m);
|
||||
auto postg = *gains(o,T) * preg;
|
||||
//printf("op %d in %f toSelf %f toOut %f\n",o,m,preg,postg);
|
||||
|
||||
out += postg;
|
||||
}
|
||||
this->out = out;
|
||||
}
|
||||
|
||||
double sampleMono() {
|
||||
process();
|
||||
return out.first + out.second;
|
||||
}
|
||||
std::pair<double,double> sampleStereo() {
|
||||
process();
|
||||
return out;
|
||||
}
|
||||
double getMono() {
|
||||
return out.first + out.second;
|
||||
}
|
||||
std::pair<double,double> getStereo() {
|
||||
return out;
|
||||
}
|
||||
std::pair<double,double> operator()(){
|
||||
process();
|
||||
return out;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* Local Variables: */
|
||||
/* mode: c++ */
|
||||
/* End: */
|
||||
/* vim: ft=cpp: */
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Filename: Envelope.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 08:41:17 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "Envelope.h"
|
||||
namespace FM {
|
||||
float Envelope::process () {
|
||||
switch (envstate) {
|
||||
case _e_off:
|
||||
if (*gate) {
|
||||
t = 0;
|
||||
envstate = _e_attack;
|
||||
return process();
|
||||
}
|
||||
break;
|
||||
case _e_attack:
|
||||
if (*gate) {
|
||||
if ( t < attack ) {
|
||||
float stepsize = (max_level - min_level) / attack;
|
||||
t++;
|
||||
return t * stepsize;
|
||||
} else {
|
||||
t = 0;
|
||||
envstate = _e_decay;
|
||||
return max_level;
|
||||
}
|
||||
} else {
|
||||
envstate = _e_attackrelease;
|
||||
return process();
|
||||
}
|
||||
break;
|
||||
case _e_decay:
|
||||
if (*gate) {
|
||||
if (t < decay) {
|
||||
float stepsize = (max_level - sustain_level) / decay;
|
||||
t++;
|
||||
return (max_level - (t * stepsize));
|
||||
|
||||
} else {
|
||||
envstate = _e_sustain;
|
||||
return sustain_level;
|
||||
}
|
||||
} else {
|
||||
envstate = _e_attackrelease;
|
||||
return process();
|
||||
}
|
||||
break;
|
||||
case _e_sustain:
|
||||
if (!sustain) {
|
||||
envstate = _e_release;
|
||||
t = 0;
|
||||
return process();
|
||||
}
|
||||
if (!*gate) {
|
||||
t = 0;
|
||||
envstate = _e_release;
|
||||
return sustain_level;
|
||||
}
|
||||
return sustain_level;
|
||||
break;
|
||||
case _e_release:
|
||||
if (*gate) {
|
||||
// reset envelope.
|
||||
envstate=_e_off;
|
||||
return process();
|
||||
}
|
||||
if (modMode) {
|
||||
return sustain_level;
|
||||
}
|
||||
if (t < release) {
|
||||
float stepsize = (sustain_level - min_level) / release;
|
||||
t++;
|
||||
return sustain_level - (stepsize * t);
|
||||
} else {
|
||||
envstate = _e_off;
|
||||
return min_level;
|
||||
}
|
||||
|
||||
break;
|
||||
case _e_attackrelease:
|
||||
if (*gate) {
|
||||
//reset envelope
|
||||
envstate=_e_off;
|
||||
return process();
|
||||
}
|
||||
return 0.0f;
|
||||
break;
|
||||
|
||||
}
|
||||
return 0.0f; // if this is reached, something went wrong or an unhandled function was used.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Filename: Envelope.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 07:48:47 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
namespace FM {
|
||||
class Envelope {
|
||||
enum EnvState {_e_off,_e_attack, _e_attackrelease, _e_decay, _e_sustain,_e_release, _e_finished};
|
||||
// Time Params
|
||||
unsigned int attack = 0; // attack length in samples
|
||||
unsigned int decay = 0; // decay length in samples
|
||||
unsigned int release = 0; // release time in samples
|
||||
bool sustain = true; // boolean if sustain is enabled.
|
||||
bool modMode = false; // boolean if we just use SL instead of minlevel till reset.
|
||||
|
||||
// Level Params
|
||||
float max_level = 1.0;
|
||||
float sustain_level = 1.0; // level that decay phase drops to.
|
||||
float min_level = 0.0;
|
||||
bool* gate; // pointer to gate
|
||||
|
||||
// Internal use
|
||||
unsigned long int t = 0; // samples;
|
||||
unsigned int smpRate; // sample rate
|
||||
EnvState envstate = _e_off; // envelope state.
|
||||
public:
|
||||
// getters
|
||||
unsigned int getAttackSamples() { return attack; }
|
||||
unsigned int getDecaySamples() { return decay; }
|
||||
unsigned int getReleaseSamples() { return release; }
|
||||
float getAttackTime() { return (double) attack / (double) smpRate; }
|
||||
float getDecayTime() { return (double) decay / (double) smpRate; }
|
||||
float getReleaseTime() { return (double) release / (double) smpRate; }
|
||||
bool getSustain() { return sustain; }
|
||||
float getMaxLevel() { return max_level; }
|
||||
float getMinLevel() { return min_level; }
|
||||
float getSustainLevel() { return sustain_level; }
|
||||
bool getModMode() { return modMode; }
|
||||
bool* getGate() { return gate; }
|
||||
// setters
|
||||
void setAttackSamples(unsigned int a) { attack = a; }
|
||||
void setAttackTime(float a) { attack = floor(smpRate * a); }
|
||||
void setDecaySamples(unsigned int d) { decay = d; }
|
||||
void setDecayTime(float d) { decay = floor(smpRate * d); }
|
||||
void setReleaseSamples(unsigned int r) { release = r; }
|
||||
void setReleaseTime(float r) { release = floor(smpRate * r); }
|
||||
void setSustain(bool s) { sustain = s; }
|
||||
void setModMode(bool m) { modMode = m; }
|
||||
void setMaxLevel(float ml) { max_level = ml; }
|
||||
void setMinLevel(float ml) { min_level = ml; }
|
||||
void setSustainLevel(float sl) { sustain_level = sl; }
|
||||
void setGate(bool* g) { gate = g; }
|
||||
void setRate(unsigned int sr) { smpRate = sr; }
|
||||
// helpers
|
||||
// note : if you make use of these functions YOU must manage their memory.
|
||||
void makeGate() { gate = (bool*) malloc(sizeof(bool)); }
|
||||
void freeGate() { free(gate); }
|
||||
// constructors
|
||||
Envelope(){}
|
||||
Envelope(unsigned int sr, unsigned int a, unsigned int d, bool s, unsigned int r, float sl, bool* g);
|
||||
// methods
|
||||
float process();
|
||||
float operator()() { return process(); }
|
||||
};
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* mode: c++ */
|
||||
/* End: */
|
||||
/* vim: ft=cpp: */
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Filename: Matrix.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 08:11:11 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <array>
|
||||
|
||||
namespace FM {
|
||||
template <class T, int N>
|
||||
class Matrix {
|
||||
public:
|
||||
std::array<std::array<T, N+1>, N> v; // gain
|
||||
std::array<T,N+1> *operator[] (int row){
|
||||
return &v[row];
|
||||
}
|
||||
T *operator()(int row, int col) {
|
||||
return &v[row][col];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* mode: c++ */
|
||||
/* End: */
|
||||
/* vim: ft=cpp: */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Filename: Operator.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 08:36:21 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Operator.h"
|
||||
namespace FM {
|
||||
void Operator::process(){
|
||||
phase += smpTime * (((*freq * mul) + detune));
|
||||
_out=last=sin((2*M_PI*phase) + _in + (fbgain*last));
|
||||
}
|
||||
double Operator::operator()(){
|
||||
process();
|
||||
elast = e();
|
||||
return elast * _out;
|
||||
}
|
||||
double Operator::operator()(double in){
|
||||
_in = in;
|
||||
process();
|
||||
elast = e();
|
||||
return elast * _out;
|
||||
}
|
||||
void Operator::setAll(double mul, double detune, double fbgain) {
|
||||
this->mul = mul;
|
||||
this->detune = detune;
|
||||
this->fbgain = fbgain;
|
||||
}
|
||||
Operator::Operator(){
|
||||
__m = true;
|
||||
freq = (double*) malloc(sizeof(double));
|
||||
gate = (bool*) malloc(sizeof(bool));
|
||||
e.setGate(gate);
|
||||
}
|
||||
Operator::Operator(double* f, bool* g) {
|
||||
gate = g;
|
||||
freq = f;
|
||||
e.setGate(gate);
|
||||
}
|
||||
Operator::Operator(double* f, bool* g, unsigned int sr) {
|
||||
gate = g;
|
||||
freq = f;
|
||||
smpRate = sr;
|
||||
smpTime = 1.0/sr;
|
||||
e.setRate(sr);
|
||||
e.setGate(gate);
|
||||
}
|
||||
Operator::~Operator(){
|
||||
if (__m) {
|
||||
free(freq);
|
||||
free(gate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Filename: Operator.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 07:57:26 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Envelope.h"
|
||||
namespace FM {
|
||||
class Operator {
|
||||
double mul = 1.0;
|
||||
double detune = 0.0;
|
||||
double fbgain = 0.0;
|
||||
bool __m;
|
||||
double *freq; // frequency
|
||||
bool *gate;
|
||||
double _in = 0.0; // fm input
|
||||
double _out = 0.0;
|
||||
double last = 0.0; // for feedback
|
||||
double phase = 0.0;
|
||||
Envelope e;
|
||||
double elast = 0.0;
|
||||
double smpTime;
|
||||
double smpRate;
|
||||
public:
|
||||
void process();
|
||||
double operator()();
|
||||
double operator()(double in);
|
||||
double out() { return elast * _out; }
|
||||
Envelope* getEnvelope() { return &e; }
|
||||
void setAll(double mul, double detune, double fbgain);
|
||||
void setMul(double mul) { this->mul = mul; }
|
||||
void setDetune(double mul) { this->mul = mul; }
|
||||
void setFeedbackLevel(double fbgain) { this->fbgain = fbgain; };
|
||||
Operator();
|
||||
Operator(double* f, bool* g);
|
||||
Operator(double* f, bool* g, unsigned int sr);
|
||||
~Operator();
|
||||
};
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* mode: c++ */
|
||||
/* End: */
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Filename: fmtest.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Version:
|
||||
* Created: Sun Mar 8 08:12:43 2020
|
||||
* Revision: None
|
||||
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Engine.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
int16_t toint16(double i) {
|
||||
double temp = i *= 32767;
|
||||
return floor(temp);
|
||||
}
|
||||
void writeBytes(FILE* file, char* bytes, unsigned int count) {
|
||||
for (int i = 0; i < count ; i++)
|
||||
putc(bytes[i],file);
|
||||
}
|
||||
int main(int argc, char** argv){
|
||||
FM::Engine<2> *f = new FM::Engine<2>();
|
||||
f->getOperator(0)->setAll(2.0,0.0,0.0);
|
||||
f->getOperator(0)->getEnvelope()->setAttackTime(1.0);
|
||||
f->getOperator(0)->getEnvelope()->setDecayTime(0.5);
|
||||
f->getOperator(0)->getEnvelope()->setMaxLevel(1.0);
|
||||
f->getOperator(0)->getEnvelope()->setModMode(true); // play until reset.
|
||||
f->getOperator(1)->getEnvelope()->setReleaseTime(2.5);
|
||||
f->getOperator(1)->setAll(1.0,0.0,0.0);
|
||||
f->setGainMatrix(0,0,0.0); // op1 fbl = 0
|
||||
f->setGainMatrix(0,1,1.0); // op1 -> op2 = 1
|
||||
f->setGainMatrix(1,0,0.0); // op2 -> op1 = 0
|
||||
f->setGainMatrix(1,2,1.0); // op2 -> out = 1
|
||||
f->freq = 440;
|
||||
f->gate = true;
|
||||
FM::Engine<2> *g = new FM::Engine<2>();
|
||||
g->getOperator(0)->setAll(2.0,0.0,0.0);
|
||||
g->getOperator(0)->getEnvelope()->setAttackTime(1.0);
|
||||
g->getOperator(0)->getEnvelope()->setDecayTime(0.5);
|
||||
g->getOperator(0)->getEnvelope()->setMaxLevel(1.0);
|
||||
g->getOperator(0)->getEnvelope()->setModMode(true); // play until reset.
|
||||
g->getOperator(1)->getEnvelope()->setReleaseTime(2.5);
|
||||
g->getOperator(1)->setAll(1.0,0.0,0.0);
|
||||
g->setGainMatrix(0,0,0.0); // op1 fbl = 0
|
||||
g->setGainMatrix(0,1,1.0); // op1 -> op2 = 1
|
||||
g->setGainMatrix(1,0,0.0); // op2 -> op1 = 0
|
||||
g->setGainMatrix(1,2,1.0); // op2 -> out = 1
|
||||
g->freq = 256;
|
||||
g->gate = true;
|
||||
FILE* w = fopen("testwav.wav", "w");
|
||||
fprintf(w,"RIFF");
|
||||
double seconds = 20;
|
||||
uint32_t srate = 44100;
|
||||
unsigned int samples= floor(seconds*srate);
|
||||
uint16_t bps = 16;
|
||||
uint16_t channels = 2;
|
||||
uint32_t datasize = ((bps/8)*channels*samples);
|
||||
uint32_t fmtsize = 16;
|
||||
uint16_t type = 1;
|
||||
uint32_t riffsize = 20 + fmtsize + datasize;
|
||||
uint32_t byterate = srate * 1 * (bps/8);
|
||||
uint16_t blockalign = channels * (bps/8);
|
||||
char* l;
|
||||
writeBytes(w,(char*) &riffsize,4);
|
||||
fprintf(w,"WAVEfmt ");
|
||||
// size
|
||||
writeBytes(w,(char*) &fmtsize,4);
|
||||
// type
|
||||
writeBytes(w,(char*) &type,2);
|
||||
writeBytes(w,(char*) &channels,2);
|
||||
writeBytes(w,(char*) &srate,4);
|
||||
writeBytes(w,(char*) &byterate,4);
|
||||
writeBytes(w,(char*) &blockalign,2);
|
||||
writeBytes(w,(char*) &bps, 2);
|
||||
fprintf(w,"data");
|
||||
writeBytes(w,(char*) &datasize, 4);
|
||||
|
||||
for (int s = 0; s < samples; s++) {
|
||||
double ld = (*f)();
|
||||
double rd = (*g)();
|
||||
int16_t l = toint16(ld/4.0);
|
||||
int16_t r = toint16(rd/4.0);
|
||||
writeBytes(w,(char*) &l,2);
|
||||
writeBytes(w,(char*) &r,2);
|
||||
}
|
||||
fclose(w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
Copyright 2020 Rachel Fae Fox
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,49 @@
|
|||
CXX ?= clang++
|
||||
SRCDIR ?= FM
|
||||
INCDIR += -I${SRCDIR}
|
||||
OBJDIR ?= FM
|
||||
BINDIR ?= bin
|
||||
INSTALLDIR ?= /usr/local/bin
|
||||
|
||||
TARGET ?= synththing
|
||||
|
||||
CFLAGS += -std=c++11
|
||||
#CFLAGS += `pkg-config --cflags portaudio-2.0`
|
||||
#LDFLAGS += `pkg-config --libs portaudio-2.0`
|
||||
|
||||
UNAME=$(shell uname -s)
|
||||
ifeq (${UNAME},FreeBSD)
|
||||
INCDIR += -I/sys/
|
||||
endif
|
||||
|
||||
SHELL=/bin/sh
|
||||
SRC = $(wildcard ${SRCDIR}/*.cpp ${SRCDIR}/*/*.cpp)
|
||||
OBJ = ${SRC:${SRCDIR}/%.cpp=${OBJDIR}/%.o}
|
||||
|
||||
|
||||
all: fmtest
|
||||
|
||||
${OBJ}: $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
|
||||
@echo CXX $<
|
||||
${CXX} -o $@ ${INCDIR} -c ${CFLAGS} ${DEFINES} $<
|
||||
|
||||
fmtest: ${OBJ}
|
||||
@echo CXX -o ${BINDIR}/fmtest
|
||||
@mkdir -p ${BINDIR}
|
||||
${CXX} ${INCDIR} -o ${BINDIR}/fmtest ${OBJ} ${LDFLAGS} ${CFLAGS} ${DEFINES}
|
||||
|
||||
clean:
|
||||
@echo cleaning
|
||||
@rm -f ${OBJ}
|
||||
|
||||
remove: clean
|
||||
@echo deleting binary
|
||||
@rm -f ${BINDIR}/${TARGET}
|
||||
@rm -r ${BINDIR}
|
||||
|
||||
install: fmtest
|
||||
mkdir -p ${INSTALLDIR}
|
||||
cp ${BINDIR}/${TARGET} ${INSTALLDIR}/${TARGET}
|
||||
chmod 4555 ${INSTALLDIR}/${TARGET}
|
||||
|
||||
|
Loading…
Reference in New Issue