✍ diale.org

Webpage of Tiago Charters de Azevedo

Início/Start Arquivo/Archive AdNauseum Notas/Notes Contact me RSS


Amplificador 1W com um Mosfet – LAMP

A construção de um amplificador de guitarra pode ser uma das experiências mais gratificantes no DIY

2017/06/16-10:57:38

Vamos então construir um amplificador de guitarra usando apenas um componente activo: um Mosfet a trabalhar em classe A.

É um amplificador minimalista inspirado nos projectos desenvolvidos e partilhados por Nelson Pass, o guru do hi-fi em classe A - https://www.passdiy.com

Quanto ao material, resume-se a 6 componentes (mais ou menos)

A ideia deste artigo é construir um pequeno power amp que soa bem quando se faz o overdrive. Note-se que apenas vamos construir um power-amp com um fantástico 1W usando um mosfet.

Circuito simplificado, circuito completo

A figura seguinte mostra o circuito completo do amplificador. Tal como está o Mosfet vê qualquer coisa como 3.5V no drain e tem um ganho, para uma corrente de repouso igual a 600mA, da ordem de 8 (ganho máximo para diferentes valores do potenciómetro P1).

Quer isto dizer que se o sinal de entrada for 0.1V à saída teremos 0.8V, o ganho é um factor multiplicativo. A impedância de entrada é da ordem dos 50 kOhms que é mais do que suficiente para ser ligada a qualquer output de um pedal de distorção ou booster e cá temos o nosso pré-amplificador para desenrascar. Os condenadores de acoplamento, de 220nF e de 1000uF, entrada e saída respectivamente, controlam a resposta em frequência do circuito. Outros pares de valores seriam possíveis para a mesma resposta em frequência mas, ao meu ouvido, soa melhor a distorção (quando se faz o overdrive) ao deixar passar graves à entrada e cortá-los à saída com um valor mais baixo de C2.

Mas isto é DIY, basta experimentar!

O mosfet tem o seu ponto de funcionamento garantido através da rede de feedback composta pela resistência R2 e o potenciómetro P1, chamada rede de Schade (1938), que liga o drain à gate.

O potenciómetro P1 é opcional, permite controlar o ponto de funcionamento do mosfet, um trimpot escondido dentro da caixa serve para ajustar o ponto de funcionamento e que ficará fixo neste caso.

E fez-se luz

Como resistência de potência vamos usar um lâmpada de carro, é a carga do componente activo, e especifica a impedância de saída do circuito. À semelhança do que acontece com os amplificadores a válvulas este amplificador tem uma impedância de saída elevada o que faz transparecer as qualidade do speaker.

Uma lâmpada comporta-se como uma resistência não linear. Quanto mais quente está, maior é a resistência. A resistência aos terminais da lâmpada não obedece à lei de Ohm. Os gráficos anteriores mostram o valor da resistência de várias lâmpadas de carro de que se podem comprar. As lâmpada típicas de médios/macha-atrás e de pisca (âmbar) têm usualmente 21W e devem ser alimentadas as 12V (curvas a preto e vermelho). Arranjei também uma lâmpada de 10W (curva a verde) e ofereceram-me uma lâmpada de empilhadora de 24V de 25W (ou será de camião?). O amplificador funcionará bem qualquer uma das lâmpadas. A resistência das lâmpada de 21W é menor e por isso deverá arranjar-se um dissipador maior. A minha escolha foi a lâmpada de 24V/25W.

Ilustração dos diversos passos de montagem

O suporte para a lâmpada é de reboque:

Dissipador:

Optei por fazer a caixa em madeira, tem dimensões (12cmx16cm) e as laterais (4.3cmx16cm). Têm espessura de 1.5cm).

A figura seguinte mostra já a caixa montada com os furos para colocar o dissipador e o farol, antes de lixada.

E usei umas calhas de alumínio de 4.3cm para colocar os jacks:

E confirma-se que está tudo bem:

E fura-se o dissipador. Note-se no círculo interior onde se vai colocar o mosfet.

Optei por montar tudo numa linha de contactos que tinha para aqui, mas podia ter usado uma stripboard:

E um spaceinvader que teimou em ajudar. Ficou tudo mais fácil a partir daqui ;)

A montagem do transístor requer algum cuidado. É necessário massa térmica e um isolador de cerâmica (ou outro).

Costumo colocar massa térmica entre o isolador e o dissipador e transístor.

E já me esquecia... a fonte de alimentação é um carregador de portátil 18V 2.23A, mas qualquer outro serve.

Notas finais

E já está! As fotografias seguintes mostram a clara vantagem de usarmos uma lâmpada: não ser necessário instalar um led on-off.

O plástico vermelho dá aquela sensação quente que tanto gostamos em amplificadores de guitarra. Os circuitos simples, e este é um caso desses, permitem identificar muito bem os efeitos que se obtêm quando se varia um parâmetro. O potenciómetroP1 permite controlar o ponto de funcionamento do mosfet permitindo controlar a distorção e compressão do sinal final amplificado. E como soa? Bom melhor mesmo é montar um!

Boas construções!

Etiquetas/Tags: guitar, audio, class a, Nelson Pass, mosfet electrónica

Electra distortion

... um projecto simples para a breadboard.

2017/05/29-22:40:51

Como primeiro projecto de utilização do suporte para a breadboard vamos construir um circuito básico de distorção com apenas um transístor: um Electra distortion. Há numerosos exemplos deste tipo de circuitos e mais umas quantas modificações que uma pesquisa na net revelará, no entanto, vou restringir-me à versão standard.

Primeiro projecto:

O primeiro projecto de utilização do suporte para a breadboard (ver artigo anterior) é este Electra distortion, uns 0.5 Eurs em componentes.

Tem a seguinte lista de material.

Material

Esquema do circuito

O esquema da distorção Electra corresponde a uma configuração em emissor comum com um par de díodos invertidos à saída. A figura seguinte mostra o screenshot do circuito implementado no software TINA-TI da Texas Instrumentes (http://www.ti.com/tool/tina-ti).

O software TINA-TI é excelente para simular circuitos e estudar algumas configurações antes de as concretizar.

Simulações usando o TINA-TI

A figura seguinte mostra a forma das tensões de entrada e saída. Note-se que a tensão produzida pelos pickups (single coil) de uma guitarra são da ordem de 0.1V (apenas uma corda, força normal) ou 0.5V para um acorde (ou bordões tocados com força). Claro que depende da localização dos pickups (neck, bridge) e até mesmo do fabricante. No entanto 100mV é um bom valor inicial para ser usado como amplitude do sinal para simulação de circuitos. Devido à baixa impedância de entrada deste pequeno circuito a resposta em frequência é dependente dos pickups usados na guitarra (aqui aplica-se os mesmos comentários que se lêem sobre o fuzz-face). O esquema anterior inclui os componentes para a simulação de um pickup de guitarra assim como os pots de volume e de tone.

A figura seguinte mostra a forma das tensões de entrada e saída para 1kHz e 0.1V de amplitude.

Um bonito sinal limitado por diodos. Soft ou hard cliping?

Podemos obter a resposta em frequência usando o mesmo software. Não tomando em consideração as características dos pickups tem-se o gráfico seguinte para o ganho em função da frequência:

Um perfil mais ou menos plano depois 100Hz (um filtro passa alto).

Se incluir a simulação dos pickups vê-se claramente o que acontece quando o circuito sobrecarrega a saída da guitarra. Tem uma resposta em frequência na banda dos médios. O circuito completo “guitarra+Electra” tem uma resposta em frequência como um filtro passa banda.

Montagem na breadboard

A montagem na breadboard é simples. São poucos componentes.

Note-se o conector DIY para a bateria feito de uma bateria velha.

É uma boa prática tomar notas sobre o circuito, terminais do transístor, especificidades da montagem, etc. E depois de testar o circuito com o amplificador adicionar umas notas extra, como soa, como reage, como se comporta com diferentes guitarras, pedais, condições atmosféricas, etc.

Fica mais ou menos assim, não é necessário estarmos preocupado com a beleza da montagem. Note-se que não tinha nenhum condensador de 100nF, os de 150nF servem perfeitamente!

Nunca é demais relembrar que as montagens em breadboard são provisórias e desde que não haja nenhum curto-circuito todas as regras são válidas!

Medições usando o osciloscópio e o gerador de sinais

É importante para estudo construção ter um osciloscópio e um gerador de sinais. Com o gerador de sinais podemos ver se as simulações que foram feitas têm alguma correspondência com o circuito montado e visualizar a resposta no osciloscópio. A concordância neste caso é razoável, com um sinal de 1kHz à entrada, o simulador parece dar mais ganho ao transístor do que aquele realmente tem, mas tudo ok. A variabilidade dos parâmetros dos transístores é normal (sim, podia escolher um com as propriedades pretendidas com algumas medições).

A figura seguinte mostra o que acontece ao sinal de saída quando se aumenta a amplitude do sinal de entrada. O sinal é “clipado” de uma forma simétrica à saída pelos díodos passando, à medida que se aumenta a amplitude do sinal, de soft-clipping a hard-cliping. Depois o transístor começa a “fugir” do seu ponto de funcionamento inicial e dá-se o hard-clipping com uma estrutura assimétrica.

O som produzido pela guitarra quando o sinal sofre este tipo de alterações é bem conhecido. O clipping simétrico possui componentes harmónicas em todas as frequências, incluindo a 3ª. Resultando num som mais áspero, cortante e até dissonante. Para amplitudes maiores o clipping torna-se assimétrico e introduz harmónicas pares (duplicação de frequência, uma oitava) suprimindo, em proporção, os harmónicos cuja frequência é tripla da fundamental, adicionando ao som uma estrutura “mais quente” e agradável.

Esta descrição pode ser muito bem vista analisando a resposta em frequência do sinal de saída, i.e. estudando as suas componentes de Fourier (matemático francês do sec. XIX), olhando para as diferentes parcelas que compõem o sinal de saída da distorção.

Para além do efeito da resposta em frequência se alterar devido à baixa impedância deste circuito relativamente à impedância dos pickups da guitarra, temos ainda o efeito da distorção. A figura seguinte mostra bem as contribuições extra de harmónicas que este pequeno circuito adiciona ao sinal. O sinal de entrada está a amarelo o de saída a azul, o sinal roxo, parte de baixo do ecrã dá-nos o peso que cada frequência tem na composição do sinal de saída.

O primeiro pico corresponde à frequência do sinal original 1kHz, o segundo à segunda harmónica de 2kHz, uma oitava acima (ver o sinal de saída deformado na parte superior do ecrã). Os picos seguintes correspondem às harmónicas seguintes 3ª , 4ª, etc.

É possível também usar a guitarra como fonte de sinal para depois visualizarmos a onda de saída no osciloscópio. O sinal a amarelo é obtido directamente do colector do transístor, o sinal azul aos terminais dos díodos.

Note-se em primeiro lugar as diferentes escalas usadas para registo dos dois sinais, em segundo lugar que é fácil ver a compressão que corresponde ao achatamento da amplitude do sinal de saída: a distorção.

Como soa?

Os 3 soundclips seguintes mostram bem como soa este pequeno circuito. Nada mal para 50 cêntimos em peças! Limpa bem reduzindo o volume da guitarra ;)

Considerações finais

O circuito com apenas um transístor é um exemplo muito relevante em como circuitos simples resultam muito bem em conjugação com instrumentos electrónicos. O exemplo também mostra como devemos ser cépticos e interrogarmos-nos relativamente aquilo que os fabricantes de efeitos para guitarra nos vendem como sendo a última criação em termos artísticos ou de mojo.

Se o DIY serve para alguma coisa para além do exercício puro de experimentação e aprendizagem é o de permitir desfazer preconceitos e falsas verdades que perpetuam a ignorância e um modo de fazer as coisas pouco claro. O que pode ser mais honesto e verdadeiro do que os resultados que se obtém com uma experiência realizada à nossa frente?

Acabo com uma lista de referências do Jack Orman (http://www.muzique.com) com algumas modificações ao circuito:

Etiquetas/Tags: guitarra, distroção, diy, breadboard

Yet another Platonic solid set

... circumscribed in a 25mm radius sphere

2017/05/25-12:35:21

Get it here: https://www.youmagine.com/designs/yet-another-platonic-solid-set

Print it, share and learn!

Etiquetas/Tags: 3dprint, 3dprinting, Platonic, regular, solid, solids, polyhedron

So you want to print a Truncated Icosahedron ?

Buckyball

2017/05/25-12:29:36

Get it here: https://www.youmagine.com/designs/truncated-icosahedron-buckyball

Print it, share and learn!

Etiquetas/Tags: buckyball, Truncated Icosahedron, Truncated, Icosahedron, 3dprint, 3dprinting

Suporte para Breadboard DIY

... para montagens de electrónica.

2017/05/24-14:04:07

Introdução

A iniciação no DIY para montagem e estudo de efeitos para guitarra, baixo ou outros instrumentos electrónicos tem sempre uma custo inicial elevado, isto porque é necessário adquirir alguma material que inclui ferramentas, transístores, circuitos integrados, transformadores, resistências, condensadores , etc, e, normalmente, uma breadboard. A breadboard é uma ferramenta de estudo e experimentação importante. Permite montar uma versão provisória de um circuito sem danificar os componentes utilizados e utiliza-los numa outra futura construção. Uma das dificuldades na montagem e avaliação de um circuito para ser usado com um instrumento musical é a necessidade de levar a montagem até ao amplificador para ser testado, para ver como soa, ou então testa-lo com um amplificador de bancada. Não é raro a breadboard cair ao chão durante os testes, puxa-se um fio, ou as fichas são pesadas e puxam a montagem que já estava a escorregar na mesa das sala ou da cozinha desmontando tudo e levando ao curto-circuito final. Assim é importante a utilização de um suporte para acomodar a breadboard na sua tarefa de teste e experimentação. Nas páginas seguintes descreve-se a construção de uma base para breadboard, não só a breadboard mas o suporte para ligar os cabos e ligação ao amplificador, alimentação, potenciómetros, etc.

A construção é relativamente simples não sendo preciso máquinas sofisticadas. São apenas necessárias ferramentas básicas: furador (eléctrico ou manual), limas (para acertar a dimensão dos furos e limar as arestas de corte da calha de alumínio), serra para metal e ferro de soldar. Caso o leitor queira montar uma engenhoca destas é sempre bom, para cortar o investimento inicial no hobby, pedir a um amigo que o ajude na construção. Dá tanto trabalho fazer uma como duas!

Uma casa para a breadboard

Material

Calhas metálicas: medição e corte

Comecemos então por marcar 20cm, o comprimento do perfil de alumínio, com um esquadro metálico e uma caneta de acetato. A calha tem 43.5mmx 23.5mm com comprimento total de 1.5m. Usei um esquadro metálico para marcar e medir, mas uma régua de plástico serve perfeitamente.

Faço as mesmas medições para as duas calhas. As arestas cortantes serão limadas durante o acabamento. depois de feitos os furos.

Uma tábua de 20cmx20cm tem as dimensões certas para acomodar o resto da montagem e adapta-se bem ao uso que se lhe quer dar. Qualquer tipo de madeira serve.

Aquela que vou usar já foi usada noutras montagens provisórias e tem uma espessura de 1.5cm e um bom peso para suportar o objectivo das suas funções. Poderíamos usar MDF, acrílico ou qualquer outro material isolante.

Calhas metálicas: furação

Optei por fazer 7 furos distanciados de 3cm (1cm das extremidades), pode parecer excessivo mas nunca se sabe o que o futuro nos reserva em futuras montagens e fica já tudo furado para não ter depois de as desmontar.

Depois de marcados a caneta os pontos marco com um punção os locais de furação (neste caso um parafuso de aço, uma broca velha também serve).

Usei uma broca de 8mm de modo conseguir colocar as todas fichas, potenciómetros e um interruptor (que dá sempre jeito). Como os jacks têm um diâmetro maior, com uma lima aumenta-se sucessivamente o diâmetro testando as dimensões entre umas quantas limadelas.

A imagem seguinte mostra um conjunto básico de coisas que podemos ligar: dois jacks, potenciómetro, ficha de alimentação e um interruptor. Note-se que já estão feitos os furos na parte inferior da calha para fixação na base de madeira.

Montagem e soldaduras

Mesmo antes de soldar os fios, e depois de lixadas e aparafusadas as calhas, podemos ver que a coisa se começa a compor. Usei uma lixa fina de metal para dar o acabamento final (lixa de água, uma lixa fina de madeira também pode ser usada, deita-se a lixa fora no fim) e uma lima para acertar as arestas cortantes nos topos de cada calha.

Costumo usar fio de telefone ou de cabo rede para as montagens na breadboard, o metro linear é barato e é possível encontra-lo em todas as lojas de bricolage a qualquer hora do dia, não vá aparecer uma vontade súbita de montar qualquer coisa e faltar material, e num metro temos disponíveis muitas cores (as cores são nossas amigas) que são óptimas e muito úteis para as montagens na breadboard. Apenas é necessário paciência para desenrolar o fio.

Optei por colocar o led directamente na breadboard mas sem dificuldade se monta na parte frontal da geringonça.

Um botão comprado na saudosa Dimofel et voilá, a engenhoca pronta a ser usada para testes e invenções!

Considerações finais

A montagem de circuitos numa breadboard é simples, permite de uma forma simples experimentar e confirmar circuitos e ideias que de outra forma não seria possível sem danificar e inutilizar componentes electrónicos. Outras abordagens de construção e design são possíveis!

Boas construções!

Etiquetas/Tags: diy, electronic, breadboard, audio

Paradroid: how I did it

Steps to build a 2.5D Paradroid for 3D printing

2017/05/03-14:11:33

It all started when I found some drawings of the character of the infamous computer game from the 80's.

The next step was obvious to me, just build a raster graphics of the beast using GNU/Octave. As is the original image needed some modification on order to be 3d-printed.

A=[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1;
1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1;    
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1;
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1;    
1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1;
1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0;
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0;
1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0;    
1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1;
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1;
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1;    
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1];
imshow(A)

print -deps -color paradroid.eps
print -dpng -color paradroid.png

So added some extra squares to get the job done.

Then used the Inkscape-to-OpenSCAD plugin and got the final 3d model, after some editing on the output code.

And it prints nicely with a resolution of 0.2mm and a 20% infill.

You can get it here: https://www.youmagine.com/designs/paradroid-ornament-key-chain

Share and enjoy!

Etiquetas/Tags: paradroid, 3d, 3dprinting, 3dprint, game, math

Números pseudo-aleatórios em LISP

Implementação em LISP de um gerador de números pseudo-aleatórios

2017/04/19-17:34:32

Uma das formas de gerar números com uma distribuição uniforme num intervalo é usando o método de congruências lineares1. Vejamos então como implementar um gerador de números pseudo-aleatórios que gera números inteiros entre 0 e m com uma distribuição uniforme latex2png equation.

A ideia é gerar uma sucessão de números com a forma latex2png equation onde2

latex2png equation

Ao valor de latex2png equation dá-se o nome de semente porque é o primeiro termo da sucessão e é usado como input para o termo seguinte. Note-se que para um mesmo latex2png equation obtém-se sempre o mesmo latex2png equation.

A sucessão de números assim obtida tem período latex2png equation e o intervalo de variação dos valores da sucessão pode ser ajustado ao intervalo latex2png equation através de

latex2png equation

A maneira mais directa é escrever

(defun rand (a c m x)
  (mod (+ (* a x) c) m))
e obtém-se
> (rand 24298 99991 199017 0)

99991

Esta não é a maneira preferível de obter um número aleatório. Queremos obter um número simplesmente fazendo (rand), mas para isso, temos de ter uma maneira de guardar os sucessivos termos da sucessão de modo a que sirvam de sementes para os termos seguintes. Assim vamos definir a variável

(defvar *r-seed* 0)
que inicializa a sucessão de sementes (ou dos próprios números pseudo-aleatórios). Esta é uma variável global e por isso está enquadrada por *. Definimos um substituto para a função anterior como
(defun rand1 ()
  (let ((a 24298)
        (c 99991)
        (m 199017))
    (cond ((<= *r-seed*  199017)
           (setf *r-seed* (mod (+ (* a *r-seed*) c) m)))
          (t
           (setf *r-seed* 0)))))
onde agora os parâmetros a, c e m são locais e estão definidos dentro da função. Assim
> (rand1)

99991

A função rand1 é simples de perceber. Depois de inicializar as quantidades a, c e m verifica se *r-seed* é menor ou igual a 199017, se sim altera o valor de *r-seed* para o novo termo da sucessão através de

(setf *r-seed* (mod (+ (* a *r-seed*) c) m))
se não
(setf *r-seed* 0)

De modo a gerar números aleatórios entre latex2png equation define-se a função

(defun rand (&optional alpha beta)
  (let ((m 199017))
    (cond ((not (and alpha beta))
           (float (/ (rand1) m)))
          (t
           (+ (* (float (/ (rand1) m)) (- beta alpha)) alpha)))))
com dois argumentos opcionais alpha e beta; se não forem dados (rand) gera números com uma distribuição uniforme no intervalo latex2png equation:
> (rand)

0.55237997

> (rand 0 2)

1.1378727

Ref:

1. D. Knuth, TAOCP

2. Master Library da TI Programable 58/59

Etiquetas/Tags: LISP, números pseudo-aleatórios

Dwarf guitar amplifier

... pics

2017/04/18-15:37:35

Found these pics of a guitar amplifier from the 70's, lovely!

Etiquetas/Tags: guitar, amp, amplifier, dwarf, DIY

OpenSCAD mode for emacs

... my hack.

2017/03/01-12:44:47

;;scad.el --- Major mode for editing SCAD files
;;; scad.el --- Major mode for editing SCAD files

;; Original author: Len Trigg <lenbok@gmail.com>
;; Maintainer: This hack is maintained by tca  <tca@diale.org>
;; Created:    20141107
;; Modified:   20141107
;; Keywords:   OpenSCAD, emacs, mode
;; URL:        http://diale.org/scad.el.html
;; Version:    0.1
;; Comments: Added a bunch of skeletons and keymaps.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;; 
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;; 
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;
;;; Commentary:
;;
;; This is a major-mode to implement the SCAD constructs and
;; font-locking for openscad
;;; Code:

;;;###autoload

(add-to-list 'auto-mode-alist '("\\.scad$" . scad-mode))

(defcustom scad-command
  '"~/Downloads/openscad-2014.03/local_inst/bin/openscad"
  "Path to openscad executable"
  :type 'string)

(defcustom scad-keywords
  '("return" "true" "false")
  "SCAD keywords."
  :type 'list
  :group 'scad-font-lock)

(defcustom scad-functions
  '("cos" "acos" "sin" "asin" "tan" "atan" "atan2"  
    "abs" "sign" "rands" "min" "max" 
    "round" "ceil" "floor" 
    "pow" "sqrt" "exp" "log" "ln"
    "str" 
    "lookup" "version" "version_num" "len" "search"
    "dxf_dim" "dxf_cross")
    "SCAD functions."
  :type 'list
  :group 'scad-font-lock)

(defcustom scad-modules
  '("child" "children" "echo" "assign" "for" "intersection_for" "if" 
    "else" "cube" "sphere" "cylinder" "polyhedron" "square" "circle" 
    "polygon" "scale" "rotate" "translate" "mirror" "multmatrix" "union"
    "difference" "intersection" "render" "color" "surface" 
    "dxf_linear_extrude" "linear_extrude" "dxf_rotate_extrude" 
    "rotate_extrude" "import_stl" 
    "import_off" "import_dxf" "import" "group" 
    "projection""minkowski" "glide" "subdiv" "hull" "resize")
    "SCAD modules."
  :type 'list
  :group 'scad-font-lock)

(defcustom scad-operators
  '("+" "-" "*" "/" "%" 
    "&&" "||" "!" 
    "<" "<=" "==" "!=" ">" ">="
    "?" ":" "=")
  "SCAD operators."
  :type 'list
  :group 'scad-font-lock)

;; "C-c letter"  are reserved for users

(defvar scad-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\t" 'scad-indent-line)
    (define-key map (kbd "C-c C-v") 'scad-open-current-buffer)
    (define-key map (kbd "C-c C-c") 'scad-output-stl)

    ;; s for solid
    (define-key map (kbd "C-c C-s c") 'scad-cylinder)
    (define-key map (kbd "C-c C-s u") 'scad-cube)
    (define-key map (kbd "C-c C-s y") 'scad-cylinder)
    (define-key map (kbd "C-c C-s p") 'scad-polyhedron)

    ;; b for Boolean
    (define-key map (kbd "C-c C-b u") 'scad-union)
    (define-key map (kbd "C-c C-b d") 'scad-difference)
    (define-key map (kbd "C-c C-b i") 'scad-intersection)

    ;; t for transformations
    (define-key map (kbd "C-c C-t t") 'scad-translate)
    (define-key map (kbd "C-c C-t r") 'scad-rotate)
    (define-key map (kbd "C-c C-t s") 'scad-scale)
    (define-key map (kbd "C-c C-t z") 'scad-resize)
    (define-key map (kbd "C-c C-t m") 'scad-mirror)
    (define-key map (kbd "C-c C-t x") 'scad-multmatrix)
    (define-key map (kbd "C-c C-t c") 'scad-color)
    (define-key map (kbd "C-c C-t h") 'scad-hull)
    (define-key map (kbd "C-c C-t k") 'scad-minkowski)

    ;; s for syntax
    (define-key map (kbd "C-c C-s m") 'scad-module)
    (define-key map (kbd "C-c C-s f") 'scad-function)
    (define-key map (kbd "C-c C-s i") 'scad-include)
    (define-key map (kbd "C-c C-s u") 'scad-use)

    ;; m for math
    ;; Is this really needed;)

    ;; f for functions
    (define-key map (kbd "C-c C-f l") 'scad-lookup)
    (define-key map (kbd "C-c C-f r") 'scad-str)
    (define-key map (kbd "C-c C-f c") 'scad-chr)
    (define-key map (kbd "C-c C-f s") 'scad-search)
    (define-key map (kbd "C-c C-f n") 'scad-version-num)
    (define-key map (kbd "C-c C-f n") 'scad-norm )
    (define-key map (kbd "C-c C-f c") 'scad-cross)
    (define-key map (kbd "C-c C-f m") 'scad-parent-module)

    ;; o for others
    (define-key map (kbd "C-c C-o r") 'scad-render)
    (define-key map (kbd "C-c C-o f") 'scad-for)
    (define-key map (kbd "C-c C-o t") 'scad-intersection-for)
    (define-key map (kbd "C-c C-o i") 'scad-if)
    (define-key map (kbd "C-c C-o a") 'scad-assign)
    (define-key map (kbd "C-c C-o m") 'scad-import)
    (define-key map (kbd "C-c C-o x") 'scad-linear-extrude)
    (define-key map (kbd "C-c C-o o") 'scad-rotate-extrude)
    (define-key map (kbd "C-c C-o s") 'scad-surface)
    (define-key map (kbd "C-c C-o p") 'scad-projection)
    (define-key map (kbd "C-c C-o c") 'scad-children)

    ;; p for on the plane
    (define-key map (kbd "C-c C-p c") 'scad-circle)
    (define-key map (kbd "C-c C-p s") 'scad-square)
    (define-key map (kbd "C-c C-p p") 'scad-polygon)

    (define-key map [return] 'newline-and-indent)
    map)
  "Keymap for `scad-mode'.")

(defvar scad-mode-syntax-table
  (let ((st (make-syntax-table)))
    ;; support comment style: “// ...” 
    ;; support comment style: “/* ... */” 
    (modify-syntax-entry ?\/ ". 124b" st)
    (modify-syntax-entry ?\n "> b" st)
    (modify-syntax-entry ?* ". 23" st)

    ;; Extra punctuation
    (modify-syntax-entry ?+  "." st)
    (modify-syntax-entry ?-  "." st)
    (modify-syntax-entry ?%  "." st)
    (modify-syntax-entry ?<  "." st)
    (modify-syntax-entry ?>  "." st)
    (modify-syntax-entry ?&  "." st)
    (modify-syntax-entry ?:  "." st)
    (modify-syntax-entry ?|  "." st)
    (modify-syntax-entry ?=  "." st)
    (modify-syntax-entry ?\;  "." st)

    ;; _ allowed in word (alternatively "_" as symbol constituent?)
    (modify-syntax-entry ?_  "w" st) st)
  "Syntax table for `scad-mode'.")

(defvar scad-keywords-regexp (regexp-opt scad-keywords 'words))
(defvar scad-modules-regexp (regexp-opt scad-modules 'words))
(defvar scad-functions-regexp (regexp-opt scad-functions 'words))
(defvar scad-operators-regexp (regexp-opt scad-operators))

(defvar scad-font-lock-keywords
  `(
    ("\\(module\\|function\\)[ \t]+\\(\\sw+\\)" (1 'font-lock-keyword-face nil) (2 'font-lock-function-name-face nil t))
    ("\\(use\\|include\\)[ \t]*<\\([^>]+\\)>" (1 'font-lock-preprocessor-face nil) (2 'font-lock-type-face nil t))
    ("<\\(\\sw+\\)>" (1 'font-lock-builtin-face nil))
    ("$\\(\\sw+\\)" (1 'font-lock-builtin-face nil))
    (,scad-keywords-regexp . font-lock-keyword-face)
    (,scad-modules-regexp .  font-lock-builtin-face)
    (,scad-functions-regexp .  font-lock-function-name-face)
    ;(,scad-operators-regexp .  font-lock-operator-face) ;; This actually looks pretty ugly
    ;("\\(\\<\\S +\\>\\)\\s *(" 1 font-lock-function-name-face t) ;; Seems to override other stuff (e.g. in comments and builtins)
    )
  "Keyword highlighting specification for `scad-mode'.")

;(defvar scad-imenu-generic-expression ...)
;(defvar scad-outline-regexp ...)

;;;###autoload
(define-derived-mode scad-mode fundamental-mode "SCAD"
  "A major mode for editing SCAD files."
  :syntax-table scad-mode-syntax-table
  (set (make-local-variable 'font-lock-defaults) '(scad-font-lock-keywords))
  (set (make-local-variable 'indent-line-function) 'scad-indent-line)
                                        ;(set (make-local-variable 'imenu-generic-expression) scad-imenu-generic-expression)
                                        ;(set (make-local-variable 'outline-regexp) scad-outline-regexp)
  ;; set comment styles for scad mode
  (set (make-local-variable 'comment-start) "//")
  (set (make-local-variable 'comment-end) "")
  (set (make-local-variable 'block-comment-start) "/*")
  (set (make-local-variable 'block-comment-end) "*/"))


;; From: http://stackoverflow.com/questions/14520073/add-words-for-dynamic-expansion-to-emacs-mode
(defun scad-prime-dabbrev ()
  "Makes a hidden scad-mode buffer containing all the scad keywords, so dabbrev expansion just works."
  (unless (get-buffer " *scad words*")
    (with-current-buffer (get-buffer-create " *scad words*")
      (scad-mode)
      (insert "module function use include")  ; Explicitly add these -- they're not in the below vars
      (insert (mapconcat 'identity (append scad-keywords scad-functions scad-modules) " ")))))

(add-hook 'scad-mode-hook 'scad-prime-dabbrev)

;;; Indentation, based on http://www.emacswiki.org/emacs/download/actionscript-mode-haas-7.0.el

(defun scad-indent-line ()
  "Indent current line of SCAD code."
  (interactive)
  (let ((savep (> (current-column) (current-indentation)))
        (indent (max (scad-calculate-indentation) 0)))
    (if savep
        (save-excursion (indent-line-to indent))
      (indent-line-to indent))))

(defun scad-calculate-indentation ()
  "Return the column to which the current line should be indented."
  (save-excursion
    (scad-maybe-skip-leading-close-delim)
    (let ((pos (point)))
      (beginning-of-line)
      (if (not (search-backward-regexp "[^\n\t\r ]" 1 0))
          0
        (progn
          (scad-maybe-skip-leading-close-delim)
          (+ (current-indentation) (* standard-indent (scad-count-scope-depth (point) pos))))))))

(defun scad-maybe-skip-leading-close-delim ()
  (beginning-of-line)
  (forward-to-indentation 0)
  (if (looking-at "\\s)")
      (forward-char)
    (beginning-of-line)))

(defun scad-face-at-point (pos)
  "Return face descriptor for char at point."
  (plist-get (text-properties-at pos) 'face))

(defun scad-count-scope-depth (rstart rend)
  "Return difference between open and close scope delimeters."
  (save-excursion
    (goto-char rstart)
    (let ((open-count 0)
          (close-count 0)
          opoint)
      (while (and (< (point) rend)
                  (progn (setq opoint (point))
                         (re-search-forward "\\s)\\|\\s(" rend t)))
        (if (= opoint (point))
            (forward-char 1)
          (cond
           ;; Don't count if in string or comment.
           ((scad-face-at-point (- (point) 1)))
           ((looking-back "\\s)")
            (setq close-count (+ close-count 1)))
           ((looking-back "\\s(")
            (setq open-count (+ open-count 1)))
           )))
      (- open-count close-count))))

(defun scad-open-current-buffer ()
  (interactive)
  (call-process scad-command nil 0 nil (buffer-file-name)))

(defun scad-output-stl ()
  (interactive)
  (async-shell-command (concat  scad-command " -o " (buffer-file-name) ".stl "
                              (buffer-file-name))))

;; Skeleton for easy editing
;; 3D
(define-skeleton scad-sphere
  "Insert sphere."
  "Sphere:"
  "sphere:(" str ");")

(define-skeleton scad-cube
  "Insert cube."
  "Cube:"
  "cube:(" str ");")

(define-skeleton scad-cylinder
  "Insert cylinder."
  "Cylinder:"
  "cylinder(" str ");")

(define-skeleton scad-polyhedron
  "Insert polyhedron."
  "Polyhedron:"
  "polyhedron(" str ");")

;; 2D

(define-skeleton scad-circle
  "Insert square."
  "Square:"
  "square(" str ");")

(define-skeleton scad-square
  "Insert square ."
  "Square:"
  "square(" str ");")

(define-skeleton scad-polygon
  "Insert polygon."
  "Polygon:"
  "Polygon(" str ");")

;; Transformations

(define-skeleton scad-translate
  "Insert translate."
  "translate:"
  "translate(" str "){"_"}")

(define-skeleton scad-rotate
  "Insert rotate."
  "rotate:"
  "rotate(" str "){"_"}")

(define-skeleton scad-scale
  "Insert scale."
  "Scale:"
  "scale(" str "){"_"}")

(define-skeleton scad-resize
  "Insert resize."
  "Resize:"
  "resize(" str "){"_"}")

(define-skeleton scad-mirror
  "Insert mirror."
  "Mirror:"
  "mirror(" str "){"_"}")

(define-skeleton scad-multmatrix
  "Insert multmatrix."
  "Multmatrix:"
  "multmatrix:(" str "){"_"}")

(define-skeleton scad-color
  "Insert color."
  "Color:"
  "color(" str "){"_"}")

(define-skeleton scad-hull
  "Insert hull."
  "Hull:"
  "hull(" str "){"_"}")

(define-skeleton scad-minkowski
  "Insert minkowski."
  "Minkowski:"
  "minkowski(){"_"}")

;; Boolean

(define-skeleton scad-union
  "Insert union."
  "Union:"
  "union(){}")

(define-skeleton scad-difference
  "Insert difference."
  "Difference:"
  "difference(){"_"}")

(define-skeleton scad-intersection
  "Insert intersection."
  "Intersection:"
  "intersection(){"_"}")

;; Syntax

(define-skeleton scad-module
  "Insert module."
  "Module:"
  "module " str "("_"){}")

(define-skeleton scad-function
  "Insert function."
  "Function:"
  "function " str "("_"){}")

(define-skeleton scad-include
  "Insert include."
  "Include:"
  "include <" str ".scad>")

(define-skeleton scad-use
  "Insert use."
  "Use:"
  "use <" str ".scad>")

;; Other

(define-skeleton scad-render
  "Insert render."
  "Render:"
  "render(){"_"}")


(define-skeleton scad-translate
  "Insert translate."
  "translate:"
  "translate(" str "){"_"}")

(define-skeleton scad-rotate
  "Insert rotate."
  "rotate:"
  "rotate(" str "){"_"}")

(define-skeleton scad-scale
  "Insert scale."
  "Scale:"
  "scale(" str "){"_"}")

(define-skeleton scad-resize
  "Insert resize."
  "Resize:"
  "resize(" str "){"_"}")

(define-skeleton scad-mirror
  "Insert mirror."
  "Mirror:"
  "mirror(" str "){"_"}")

(define-skeleton scad-multmatrix
  "Insert multmatrix."
  "Multmatrix:"
  "multmatrix:(" str "){"_"}")

(define-skeleton scad-color
  "Insert color."
  "Color:"
  "color(" str "){"_"}")

(define-skeleton scad-hull
  "Insert hull."
  "Hull:"
  "hull(" str "){"_"}")

(define-skeleton scad-minkowski
  "Insert minkowski."
  "Minkowski:"
  "minkowski(){"_"}")

;; Boolean

(define-skeleton scad-union
  "Insert union."
  "Union:"
  "union(){}")

(define-skeleton scad-difference
  "Insert difference."
  "Difference:"
  "difference(){"_"}")

(define-skeleton scad-intersection
  "Insert intersection."
  "Intersection:"
  "intersection(){"_"}")

;; Syntax

(define-skeleton scad-module
  "Insert module."
  "Module:"
  "module " str "("_"){}")

(define-skeleton scad-function
  "Insert function."
  "Function:"
  "function " str "("_"){}")

(define-skeleton scad-include
  "Insert include."
  "Include:"
  "include <" str ".scad>")

(define-skeleton scad-use
  "Insert use."
  "Use:"
  "use <" str ".scad>")

;; Other

(define-skeleton scad-render
  "Insert render."
  "Render:"
  "render(){"_"}")

(define-skeleton scad-for
  "Insert for."
  "For:"
  "for  (i=" str ")" "{" _ "}")
  

;; (define-skeleton scad-
;;   "Insert ."
;;   ":"
;;   "(" str ");")


(provide 'scad)
;;; scad-mode.el ends here

Enjoy.

Etiquetas/Tags: emacs, openscad

Guitar fuzzbox under 3$

Craig Anderton, Popular Electronics, January 1967

2017/02/10-14:03:34

Etiquetas/Tags: fuzz, guitar, audio

Palavras chave/keywords: página pessoal, blog

Criado/Created: NaN

Última actualização/Last updated: 16-06-2017 [10:58]


GNU/Emacs

1999-2017 (ç) Tiago Charters de Azevedo

São permitidas cópias textuais parciais/integrais em qualquer meio com/sem alterações desde que se mantenha este aviso.

Verbatim copying and redistribution of this entire page are permitted provided this notice is preserved.